Merge branch 'dev' of https://gitee.com/yudaocode/yudao-ui-admin-vue3
commit
efbc51659b
|
|
@ -106,6 +106,11 @@ export const copyTask = async (data: any) => {
|
||||||
return await request.put({ url: '/bpm/task/copy', data })
|
return await request.put({ url: '/bpm/task/copy', data })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 撤回
|
||||||
|
export const withdrawTask = async (taskId: string) => {
|
||||||
|
return await request.put({ url: '/bpm/task/withdraw', params: { taskId } })
|
||||||
|
}
|
||||||
|
|
||||||
// 获取我的待办任务
|
// 获取我的待办任务
|
||||||
export const myTodoTask = async (processInstanceId: string) => {
|
export const myTodoTask = async (processInstanceId: string) => {
|
||||||
return await request.get({ url: '/bpm/task/my-todo?processInstanceId=' + processInstanceId })
|
return await request.get({ url: '/bpm/task/my-todo?processInstanceId=' + processInstanceId })
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,9 @@ export interface MailLogVO {
|
||||||
id: number
|
id: number
|
||||||
userId: number
|
userId: number
|
||||||
userType: number
|
userType: number
|
||||||
toMail: string
|
toMails: string[]
|
||||||
|
ccMails?: string[]
|
||||||
|
bccMails?: string[]
|
||||||
accountId: number
|
accountId: number
|
||||||
fromMail: string
|
fromMail: string
|
||||||
templateId: number
|
templateId: number
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,9 @@ export interface MailTemplateVO {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MailSendReqVO {
|
export interface MailSendReqVO {
|
||||||
mail: string
|
toMails: string[]
|
||||||
|
ccMails?: string[]
|
||||||
|
bccMails?: string[]
|
||||||
templateCode: string
|
templateCode: string
|
||||||
templateParams: Map<String, Object>
|
templateParams: Map<String, Object>
|
||||||
}
|
}
|
||||||
|
|
@ -46,7 +48,10 @@ export const deleteMailTemplate = async (id: number) => {
|
||||||
|
|
||||||
// 批量删除邮件模版
|
// 批量删除邮件模版
|
||||||
export const deleteMailTemplateList = async (ids: number[]) => {
|
export const deleteMailTemplateList = async (ids: number[]) => {
|
||||||
return await request.delete({ url: '/system/mail-template/delete-list', params: { ids: ids.join(',') } })
|
return await request.delete({
|
||||||
|
url: '/system/mail-template/delete-list',
|
||||||
|
params: { ids: ids.join(',') }
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 发送邮件
|
// 发送邮件
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
:group="{ name: 'component', pull: 'clone', put: false }"
|
:group="{ name: 'component', pull: 'clone', put: false }"
|
||||||
:clone="handleCloneComponent"
|
:clone="handleCloneComponent"
|
||||||
:animation="200"
|
:animation="200"
|
||||||
:force-fallback="true"
|
:force-fallback="false"
|
||||||
>
|
>
|
||||||
<template #item="{ element }">
|
<template #item="{ element }">
|
||||||
<div>
|
<div>
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@
|
||||||
<draggable
|
<draggable
|
||||||
v-model="pageComponents"
|
v-model="pageComponents"
|
||||||
:animation="200"
|
:animation="200"
|
||||||
:force-fallback="true"
|
:force-fallback="false"
|
||||||
class="page-prop-area drag-area"
|
class="page-prop-area drag-area"
|
||||||
filter=".component-toolbar"
|
filter=".component-toolbar"
|
||||||
ghost-class="draggable-ghost"
|
ghost-class="draggable-ghost"
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
<el-text type="info" size="small"> 拖动左上角的小圆点可对其排序 </el-text>
|
<el-text type="info" size="small"> 拖动左上角的小圆点可对其排序 </el-text>
|
||||||
<VueDraggable
|
<VueDraggable
|
||||||
:list="formData"
|
:list="formData"
|
||||||
:force-fallback="true"
|
:force-fallback="false"
|
||||||
:animation="200"
|
:animation="200"
|
||||||
handle=".drag-icon"
|
handle=".drag-icon"
|
||||||
class="m-t-8px"
|
class="m-t-8px"
|
||||||
|
|
|
||||||
|
|
@ -236,7 +236,7 @@
|
||||||
<el-divider />
|
<el-divider />
|
||||||
<div>
|
<div>
|
||||||
<el-button type="primary" @click="saveConfig">确 定</el-button>
|
<el-button type="primary" @click="saveConfig">确 定</el-button>
|
||||||
<el-button @click="closeDrawer">取 消</el-button>
|
<el-button @click="cancelConfig">取 消</el-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-drawer>
|
</el-drawer>
|
||||||
|
|
@ -467,6 +467,13 @@ const saveConfig = async () => {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 取消配置 */
|
||||||
|
const cancelConfig = () => {
|
||||||
|
// 恢复原来的配置
|
||||||
|
currentNode.value.triggerSetting = originalSetting
|
||||||
|
closeDrawer()
|
||||||
|
}
|
||||||
|
|
||||||
/** 获取节点展示内容 */
|
/** 获取节点展示内容 */
|
||||||
const getShowText = (): string => {
|
const getShowText = (): string => {
|
||||||
let showText = ''
|
let showText = ''
|
||||||
|
|
@ -498,7 +505,7 @@ const getShowText = (): string => {
|
||||||
/** 显示触发器节点配置, 由父组件传过来 */
|
/** 显示触发器节点配置, 由父组件传过来 */
|
||||||
const showTriggerNodeConfig = (node: SimpleFlowNode) => {
|
const showTriggerNodeConfig = (node: SimpleFlowNode) => {
|
||||||
nodeName.value = node.name
|
nodeName.value = node.name
|
||||||
originalSetting = node.triggerSetting ? JSON.parse(JSON.stringify(node.triggerSetting)) : {}
|
originalSetting = cloneDeep(node.triggerSetting)
|
||||||
if (node.triggerSetting) {
|
if (node.triggerSetting) {
|
||||||
configForm.value = {
|
configForm.value = {
|
||||||
type: node.triggerSetting.type,
|
type: node.triggerSetting.type,
|
||||||
|
|
|
||||||
|
|
@ -36,14 +36,15 @@
|
||||||
* Verify 验证码组件
|
* Verify 验证码组件
|
||||||
* @description 分发验证码使用
|
* @description 分发验证码使用
|
||||||
* */
|
* */
|
||||||
import { VerifyPoints, VerifySlide } from './Verify'
|
import {VerifyPictureWord, VerifyPoints, VerifySlide} from './Verify'
|
||||||
import { computed, ref, toRefs, watchEffect } from 'vue'
|
import { computed, ref, toRefs, watchEffect } from 'vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Vue3Verify',
|
name: 'Vue3Verify',
|
||||||
components: {
|
components: {
|
||||||
VerifySlide,
|
VerifySlide,
|
||||||
VerifyPoints
|
VerifyPoints,
|
||||||
|
VerifyPictureWord
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
captchaType: {
|
captchaType: {
|
||||||
|
|
@ -118,6 +119,10 @@ export default {
|
||||||
}
|
}
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
switch (captchaType.value) {
|
switch (captchaType.value) {
|
||||||
|
case 'pictureWord':
|
||||||
|
verifyType.value = '3'
|
||||||
|
componentType.value = 'VerifyPictureWord'
|
||||||
|
break
|
||||||
case 'blockPuzzle':
|
case 'blockPuzzle':
|
||||||
verifyType.value = '2'
|
verifyType.value = '2'
|
||||||
componentType.value = 'VerifySlide'
|
componentType.value = 'VerifySlide'
|
||||||
|
|
@ -438,4 +443,4 @@ export default {
|
||||||
content: ' ';
|
content: ' ';
|
||||||
inset: 0;
|
inset: 0;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -0,0 +1,196 @@
|
||||||
|
<template>
|
||||||
|
<div style="position: relative">
|
||||||
|
<div class="verify-img-out">
|
||||||
|
<div
|
||||||
|
:style="{
|
||||||
|
width: setSize.imgWidth,
|
||||||
|
height: setSize.imgHeight,
|
||||||
|
'background-size': setSize.imgWidth + ' ' + setSize.imgHeight,
|
||||||
|
'margin-bottom': vSpace + 'px'
|
||||||
|
}"
|
||||||
|
class="verify-img-panel"
|
||||||
|
>
|
||||||
|
<div v-show="showRefresh" class="verify-refresh" style="z-index: 3" @click="refresh">
|
||||||
|
<i class="iconfont icon-refresh"></i>
|
||||||
|
</div>
|
||||||
|
<img
|
||||||
|
@click="refresh"
|
||||||
|
ref="canvas"
|
||||||
|
:src="'data:image/png;base64,' + verificationCodeImg"
|
||||||
|
alt=""
|
||||||
|
style="display: block; width: 100%; height: 100%"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
:style="{
|
||||||
|
width: setSize.imgWidth,
|
||||||
|
color: barAreaColor,
|
||||||
|
'border-color': barAreaBorderColor
|
||||||
|
// 'line-height': barSize.height
|
||||||
|
}"
|
||||||
|
class="verify-bar-area"
|
||||||
|
>
|
||||||
|
<div class="verify-msg">{{ text }}</div>
|
||||||
|
<div
|
||||||
|
:style="{
|
||||||
|
'line-height': barSize.height
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<input class="verify-input" type="text" v-model="userCode" />
|
||||||
|
</div>
|
||||||
|
<button type="button" class="verify-btn" @click="submit" :disabled="checking">{{
|
||||||
|
t('captcha.verify')
|
||||||
|
}}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup type="text/babel">
|
||||||
|
/**
|
||||||
|
* VerifyPictureWord
|
||||||
|
* @description 输入文字
|
||||||
|
* */
|
||||||
|
import { resetSize } from '../utils/util'
|
||||||
|
import { aesEncrypt } from '../utils/ase'
|
||||||
|
import { getCode, reqCheck } from '@/api/login'
|
||||||
|
import { getCurrentInstance, nextTick, onMounted, reactive, ref, toRefs } from 'vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
// 弹出式 pop,固定 fixed
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
default: 'fixed'
|
||||||
|
},
|
||||||
|
captchaType: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
// 间隔
|
||||||
|
vSpace: {
|
||||||
|
type: Number,
|
||||||
|
default: 5
|
||||||
|
},
|
||||||
|
imgSize: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {
|
||||||
|
width: '310px',
|
||||||
|
height: '155px'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
barSize: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {
|
||||||
|
width: '310px',
|
||||||
|
height: '40px'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
const { mode, captchaType } = toRefs(props)
|
||||||
|
const { proxy } = getCurrentInstance()
|
||||||
|
let secretKey = ref(''), // 后端返回的ase加密秘钥
|
||||||
|
userCode = ref(''), // 用户输入的验证码 暂存至pointJson,无需加密
|
||||||
|
verificationCodeImg = ref(''), // 后端获取到的背景图片
|
||||||
|
backToken = ref(''), // 后端返回的token值
|
||||||
|
setSize = reactive({
|
||||||
|
imgHeight: 0,
|
||||||
|
imgWidth: 0,
|
||||||
|
barHeight: 0,
|
||||||
|
barWidth: 0
|
||||||
|
}),
|
||||||
|
text = ref(''),
|
||||||
|
barAreaColor = ref('#000'),
|
||||||
|
barAreaBorderColor = ref('#ddd'),
|
||||||
|
showRefresh = ref(true),
|
||||||
|
// bindingClick = ref(true)
|
||||||
|
checking = ref(false)
|
||||||
|
|
||||||
|
const init = () => {
|
||||||
|
// 加载页面
|
||||||
|
getPicture()
|
||||||
|
nextTick(() => {
|
||||||
|
let { imgHeight, imgWidth, barHeight, barWidth } = resetSize(proxy)
|
||||||
|
setSize.imgHeight = imgHeight
|
||||||
|
setSize.imgWidth = imgWidth
|
||||||
|
setSize.barHeight = barHeight
|
||||||
|
setSize.barWidth = barWidth
|
||||||
|
proxy.$parent.$emit('ready', proxy)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
onMounted(() => {
|
||||||
|
// 禁止拖拽
|
||||||
|
init()
|
||||||
|
proxy.$el.onselectstart = function () {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const canvas = ref(null)
|
||||||
|
|
||||||
|
const submit = () => {
|
||||||
|
checking.value = true
|
||||||
|
// 发送后端请求
|
||||||
|
const captchaVerification = secretKey.value
|
||||||
|
? aesEncrypt(backToken.value + '---' + userCode.value, secretKey.value)
|
||||||
|
: backToken.value + '---' + userCode.value
|
||||||
|
let data = {
|
||||||
|
captchaType: captchaType.value,
|
||||||
|
pointJson: userCode.value,
|
||||||
|
token: backToken.value
|
||||||
|
}
|
||||||
|
reqCheck(data).then((res) => {
|
||||||
|
if (res.repCode === '0000') {
|
||||||
|
barAreaColor.value = '#4cae4c'
|
||||||
|
barAreaBorderColor.value = '#5cb85c'
|
||||||
|
text.value = t('captcha.success')
|
||||||
|
// bindingClick.value = false
|
||||||
|
if (mode.value === 'pop') {
|
||||||
|
setTimeout(() => {
|
||||||
|
proxy.$parent.clickShow = false
|
||||||
|
refresh()
|
||||||
|
}, 1500)
|
||||||
|
}
|
||||||
|
proxy.$parent.$emit('success', { captchaVerification })
|
||||||
|
} else {
|
||||||
|
proxy.$parent.$emit('error', proxy)
|
||||||
|
barAreaColor.value = '#d9534f'
|
||||||
|
barAreaBorderColor.value = '#d9534f'
|
||||||
|
text.value = t('captcha.fail')
|
||||||
|
setTimeout(() => {
|
||||||
|
refresh()
|
||||||
|
}, 700)
|
||||||
|
}
|
||||||
|
checking.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const refresh = async function () {
|
||||||
|
barAreaColor.value = '#000'
|
||||||
|
barAreaBorderColor.value = '#ddd'
|
||||||
|
checking.value = false
|
||||||
|
|
||||||
|
userCode.value = ''
|
||||||
|
|
||||||
|
await getPicture()
|
||||||
|
showRefresh.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 请求背景图片和验证图片
|
||||||
|
const getPicture = async () => {
|
||||||
|
let data = {
|
||||||
|
captchaType: captchaType.value
|
||||||
|
}
|
||||||
|
const res = await getCode(data)
|
||||||
|
if (res.repCode === '0000') {
|
||||||
|
verificationCodeImg.value = res.repData.originalImageBase64
|
||||||
|
backToken.value = res.repData.token
|
||||||
|
secretKey.value = res.repData.secretKey
|
||||||
|
text.value = t('captcha.code')
|
||||||
|
} else {
|
||||||
|
text.value = res.repMsg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import VerifySlide from './VerifySlide.vue'
|
import VerifySlide from './VerifySlide.vue'
|
||||||
import VerifyPoints from './VerifyPoints.vue'
|
import VerifyPoints from './VerifyPoints.vue'
|
||||||
|
import VerifyPictureWord from './VerifyPictureWord.vue'
|
||||||
|
|
||||||
export { VerifySlide, VerifyPoints }
|
export { VerifySlide, VerifyPoints, VerifyPictureWord }
|
||||||
|
|
@ -146,9 +146,11 @@ export default {
|
||||||
invalidTenantName:"Invalid Tenant Name"
|
invalidTenantName:"Invalid Tenant Name"
|
||||||
},
|
},
|
||||||
captcha: {
|
captcha: {
|
||||||
|
verify: 'Verify',
|
||||||
verification: 'Please complete security verification',
|
verification: 'Please complete security verification',
|
||||||
slide: 'Swipe right to complete verification',
|
slide: 'Swipe right to complete verification',
|
||||||
point: 'Please click',
|
point: 'Please click',
|
||||||
|
code: 'Please enter the verification code',
|
||||||
success: 'Verification succeeded',
|
success: 'Verification succeeded',
|
||||||
fail: 'verification failed'
|
fail: 'verification failed'
|
||||||
},
|
},
|
||||||
|
|
@ -457,4 +459,4 @@ export default {
|
||||||
btn_zoom_out: 'Zoom out',
|
btn_zoom_out: 'Zoom out',
|
||||||
preview: 'Preivew'
|
preview: 'Preivew'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -147,9 +147,11 @@ export default {
|
||||||
invalidTenantName: '无效的租户名称'
|
invalidTenantName: '无效的租户名称'
|
||||||
},
|
},
|
||||||
captcha: {
|
captcha: {
|
||||||
|
verify: '验证',
|
||||||
verification: '请完成安全验证',
|
verification: '请完成安全验证',
|
||||||
slide: '向右滑动完成验证',
|
slide: '向右滑动完成验证',
|
||||||
point: '请依次点击',
|
point: '请依次点击',
|
||||||
|
code: '请输入验证码',
|
||||||
success: '验证成功',
|
success: '验证成功',
|
||||||
fail: '验证失败'
|
fail: '验证失败'
|
||||||
},
|
},
|
||||||
|
|
@ -453,4 +455,4 @@ export default {
|
||||||
preview: '预览'
|
preview: '预览'
|
||||||
},
|
},
|
||||||
'OAuth 2.0': 'OAuth 2.0' // 避免菜单名是 OAuth 2.0 时,一直 warn 报错
|
'OAuth 2.0': 'OAuth 2.0' // 避免菜单名是 OAuth 2.0 时,一直 warn 报错
|
||||||
}
|
}
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
* 针对 https://github.com/xaboy/form-create-designer 封装的工具类
|
* 针对 https://github.com/xaboy/form-create-designer 封装的工具类
|
||||||
*/
|
*/
|
||||||
import { isRef } from 'vue'
|
import { isRef } from 'vue'
|
||||||
|
import formCreate from '@form-create/element-ui'
|
||||||
|
|
||||||
// 编码表单 Conf
|
// 编码表单 Conf
|
||||||
export const encodeConf = (designerRef: object) => {
|
export const encodeConf = (designerRef: object) => {
|
||||||
|
|
@ -24,7 +25,7 @@ export const encodeFields = (designerRef: object) => {
|
||||||
export const decodeFields = (fields: string[]) => {
|
export const decodeFields = (fields: string[]) => {
|
||||||
const rule: object[] = []
|
const rule: object[] = []
|
||||||
fields.forEach((item) => {
|
fields.forEach((item) => {
|
||||||
rule.push(JSON.parse(item))
|
rule.push(formCreate.parseJson(item))
|
||||||
})
|
})
|
||||||
return rule
|
return rule
|
||||||
}
|
}
|
||||||
|
|
@ -32,7 +33,7 @@ export const decodeFields = (fields: string[]) => {
|
||||||
// 设置表单的 Conf 和 Fields,适用 FcDesigner 场景
|
// 设置表单的 Conf 和 Fields,适用 FcDesigner 场景
|
||||||
export const setConfAndFields = (designerRef: object, conf: string, fields: string) => {
|
export const setConfAndFields = (designerRef: object, conf: string, fields: string) => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
designerRef.value.setOption(JSON.parse(conf))
|
designerRef.value.setOption(formCreate.parseJson(conf))
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
designerRef.value.setRule(decodeFields(fields))
|
designerRef.value.setRule(decodeFields(fields))
|
||||||
}
|
}
|
||||||
|
|
@ -49,154 +50,10 @@ export const setConfAndFields2 = (
|
||||||
detailPreview = detailPreview.value
|
detailPreview = detailPreview.value
|
||||||
}
|
}
|
||||||
|
|
||||||
// 修复所有函数类型(解决设计器保存后函数变成字符串的问题)。例如说:
|
|
||||||
// https://t.zsxq.com/rADff
|
|
||||||
// https://t.zsxq.com/ZfbGt
|
|
||||||
// https://t.zsxq.com/mHOoj
|
|
||||||
// https://t.zsxq.com/BSylB
|
|
||||||
const option = JSON.parse(conf)
|
|
||||||
const rule = decodeFields(fields)
|
|
||||||
// 🔧 修复所有函数类型 - 解决设计器保存后函数变成字符串的问题
|
|
||||||
const fixFunctions = (obj: any) => {
|
|
||||||
if (obj && typeof obj === 'object') {
|
|
||||||
Object.keys(obj).forEach((key) => {
|
|
||||||
// 检查是否是函数相关的属性
|
|
||||||
if (isFunctionProperty(key)) {
|
|
||||||
// 如果不是函数类型,重新构建为函数
|
|
||||||
if (typeof obj[key] !== 'function') {
|
|
||||||
obj[key] = createDefaultFunction(key)
|
|
||||||
}
|
|
||||||
} else if (typeof obj[key] === 'object' && obj[key] !== null) {
|
|
||||||
// 递归处理嵌套对象
|
|
||||||
fixFunctions(obj[key])
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 判断是否是函数属性
|
|
||||||
const isFunctionProperty = (key: string): boolean => {
|
|
||||||
const functionKeys = [
|
|
||||||
'beforeFetch', // 请求前处理
|
|
||||||
'afterFetch', // 请求后处理
|
|
||||||
'onSubmit', // 表单提交
|
|
||||||
'onReset', // 表单重置
|
|
||||||
'onChange', // 值变化
|
|
||||||
'onInput', // 输入事件
|
|
||||||
'onClick', // 点击事件
|
|
||||||
'onFocus', // 获取焦点
|
|
||||||
'onBlur', // 失去焦点
|
|
||||||
'onMounted', // 组件挂载
|
|
||||||
'onCreated', // 组件创建
|
|
||||||
'onReload', // 重新加载
|
|
||||||
'remoteMethod', // 远程搜索方法
|
|
||||||
'parseFunc', // 解析函数
|
|
||||||
'validator', // 验证器
|
|
||||||
'asyncValidator', // 异步验证器
|
|
||||||
'formatter', // 格式化函数
|
|
||||||
'parser', // 解析函数
|
|
||||||
'beforeUpload', // 上传前处理
|
|
||||||
'onSuccess', // 成功回调
|
|
||||||
'onError', // 错误回调
|
|
||||||
'onProgress', // 进度回调
|
|
||||||
'onPreview', // 预览回调
|
|
||||||
'onRemove', // 移除回调
|
|
||||||
'onExceed', // 超出限制回调
|
|
||||||
'filterMethod', // 过滤方法
|
|
||||||
'sortMethod', // 排序方法
|
|
||||||
'loadData', // 加载数据
|
|
||||||
'renderContent', // 渲染内容
|
|
||||||
'render' // 渲染函数
|
|
||||||
]
|
|
||||||
// 检查是否以函数相关前缀开头
|
|
||||||
const functionPrefixes = ['on', 'before', 'after', 'handle']
|
|
||||||
return functionKeys.includes(key) || functionPrefixes.some((prefix) => key.startsWith(prefix))
|
|
||||||
}
|
|
||||||
// 根据函数名创建默认函数
|
|
||||||
const createDefaultFunction = (key: string): Function => {
|
|
||||||
switch (key) {
|
|
||||||
case 'beforeFetch':
|
|
||||||
return (config: any) => {
|
|
||||||
// 添加 Token 认证头。例如说:
|
|
||||||
// https://t.zsxq.com/hK3FO
|
|
||||||
const token = localStorage.getItem('token')
|
|
||||||
if (token) {
|
|
||||||
config.headers = {
|
|
||||||
...config.headers,
|
|
||||||
Authorization: 'Bearer ' + token
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 添加通用请求头
|
|
||||||
config.headers = {
|
|
||||||
...config.headers,
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'X-Requested-With': 'XMLHttpRequest'
|
|
||||||
}
|
|
||||||
// 添加时间戳防止缓存
|
|
||||||
config.params = {
|
|
||||||
...config.params,
|
|
||||||
_t: Date.now()
|
|
||||||
}
|
|
||||||
return config
|
|
||||||
}
|
|
||||||
case 'afterFetch':
|
|
||||||
return (data: any) => {
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
case 'onSubmit':
|
|
||||||
return (_formData: any) => {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
case 'onReset':
|
|
||||||
return () => {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
case 'onChange':
|
|
||||||
return (_value: any, _oldValue: any) => {}
|
|
||||||
case 'remoteMethod':
|
|
||||||
return (query: string) => {
|
|
||||||
console.log('remoteMethod被调用:', query)
|
|
||||||
}
|
|
||||||
case 'parseFunc':
|
|
||||||
return (data: any) => {
|
|
||||||
// 默认解析逻辑:如果是数组直接返回,否则尝试获取list属性
|
|
||||||
if (Array.isArray(data)) {
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
return data?.list || data?.data || []
|
|
||||||
}
|
|
||||||
case 'validator':
|
|
||||||
return (_rule: any, _value: any, callback: Function) => {
|
|
||||||
callback()
|
|
||||||
}
|
|
||||||
case 'beforeUpload':
|
|
||||||
return (_file: any) => {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
// 通用默认函数
|
|
||||||
return (...args: any[]) => {
|
|
||||||
// 对于事件处理函数,返回true表示继续执行
|
|
||||||
if (key.startsWith('on') || key.startsWith('handle')) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// 对于其他函数,返回第一个参数(通常是数据传递)
|
|
||||||
return args[0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 修复 option 中的所有函数
|
|
||||||
fixFunctions(option)
|
|
||||||
// 修复 rule 中的所有函数(包括组件的 props)
|
|
||||||
if (Array.isArray(rule)) {
|
|
||||||
rule.forEach((item: any) => {
|
|
||||||
fixFunctions(item)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
detailPreview.option = option
|
detailPreview.option = formCreate.parseJson(conf)
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
detailPreview.rule = rule
|
detailPreview.rule = decodeFields(fields)
|
||||||
|
|
||||||
if (value) {
|
if (value) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
|
|
||||||
|
|
@ -185,7 +185,7 @@ const { push } = useRouter()
|
||||||
const permissionStore = usePermissionStore()
|
const permissionStore = usePermissionStore()
|
||||||
const loginLoading = ref(false)
|
const loginLoading = ref(false)
|
||||||
const verify = ref()
|
const verify = ref()
|
||||||
const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字
|
const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字 pictureWord 文字验证码
|
||||||
|
|
||||||
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.LOGIN)
|
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.LOGIN)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -143,7 +143,7 @@ const iconCircleCheck = useIcon({ icon: 'ep:circle-check' })
|
||||||
const { validForm } = useFormValid(formSmsResetPassword)
|
const { validForm } = useFormValid(formSmsResetPassword)
|
||||||
const { handleBackLogin, getLoginState, setLoginState } = useLoginState()
|
const { handleBackLogin, getLoginState, setLoginState } = useLoginState()
|
||||||
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.RESET_PASSWORD)
|
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.RESET_PASSWORD)
|
||||||
const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字
|
const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字 pictureWord 文字验证码
|
||||||
|
|
||||||
const validatePass2 = (_rule, value, callback) => {
|
const validatePass2 = (_rule, value, callback) => {
|
||||||
if (value === '') {
|
if (value === '') {
|
||||||
|
|
|
||||||
|
|
@ -47,10 +47,7 @@
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col
|
<el-col :span="24" class="px-10px mt-[-20px] mb-[-20px]">
|
||||||
:span="24"
|
|
||||||
class="px-10px mt-[-20px] mb-[-20px]"
|
|
||||||
>
|
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-row justify="space-between" style="width: 100%">
|
<el-row justify="space-between" style="width: 100%">
|
||||||
<el-col :span="6">
|
<el-col :span="6">
|
||||||
|
|
@ -177,7 +174,7 @@ const permissionStore = usePermissionStore()
|
||||||
const redirect = ref<string>('')
|
const redirect = ref<string>('')
|
||||||
const loginLoading = ref(false)
|
const loginLoading = ref(false)
|
||||||
const verify = ref()
|
const verify = ref()
|
||||||
const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字
|
const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字 pictureWord 文字验证码
|
||||||
|
|
||||||
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.LOGIN)
|
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.LOGIN)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,7 @@ const permissionStore = usePermissionStore()
|
||||||
const redirect = ref<string>('')
|
const redirect = ref<string>('')
|
||||||
const loginLoading = ref(false)
|
const loginLoading = ref(false)
|
||||||
const verify = ref()
|
const verify = ref()
|
||||||
const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字
|
const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字 pictureWord 文字验证码
|
||||||
|
|
||||||
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.REGISTER)
|
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.REGISTER)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,17 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item class="mb-20px">
|
||||||
|
<template #label>
|
||||||
|
<el-text size="large" tag="b">审批人权限</el-text>
|
||||||
|
</template>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<el-checkbox v-model="modelData.allowWithdrawTask" label="允许审批人撤回任务" />
|
||||||
|
<div class="ml-22px">
|
||||||
|
<el-text type="info"> 审批人可撤回正在审批节点的前一节点 </el-text>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item v-if="modelData.processIdRule" class="mb-20px">
|
<el-form-item v-if="modelData.processIdRule" class="mb-20px">
|
||||||
<template #label>
|
<template #label>
|
||||||
<el-text size="large" tag="b">流程编码</el-text>
|
<el-text size="large" tag="b">流程编码</el-text>
|
||||||
|
|
@ -232,34 +243,6 @@ import { ProcessVariableEnum } from '@/components/SimpleProcessDesignerV2/src/co
|
||||||
import HttpRequestSetting from '@/components/SimpleProcessDesignerV2/src/nodes-config/components/HttpRequestSetting.vue'
|
import HttpRequestSetting from '@/components/SimpleProcessDesignerV2/src/nodes-config/components/HttpRequestSetting.vue'
|
||||||
|
|
||||||
const modelData = defineModel<any>()
|
const modelData = defineModel<any>()
|
||||||
const formFields = ref<string[]>([])
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
// 流程表单 ID
|
|
||||||
modelFormId: {
|
|
||||||
type: Number,
|
|
||||||
required: false,
|
|
||||||
default: undefined,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
// 监听 modelFormId 变化
|
|
||||||
watch(
|
|
||||||
() => props.modelFormId,
|
|
||||||
async (newVal) => {
|
|
||||||
if (newVal) {
|
|
||||||
const form = await FormApi.getForm(newVal);
|
|
||||||
formFields.value = form?.fields;
|
|
||||||
} else {
|
|
||||||
// 如果 modelFormId 为空,清空表单字段
|
|
||||||
formFields.value = [];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ immediate: true },
|
|
||||||
);
|
|
||||||
// 暴露给子组件使用
|
|
||||||
provide('formFields', formFields)
|
|
||||||
|
|
||||||
/** 自定义 ID 流程编码 */
|
/** 自定义 ID 流程编码 */
|
||||||
const timeOptions = ref([
|
const timeOptions = ref([
|
||||||
|
|
@ -374,10 +357,10 @@ const handleTaskAfterTriggerEnableChange = (val: boolean | string | number) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 表单选项 */
|
/** 已解析表单字段 */
|
||||||
const formField = ref<Array<{ field: string; title: string }>>([])
|
const formFields = ref<Array<{ field: string; title: string }>>([])
|
||||||
const formFieldOptions4Title = computed(() => {
|
const formFieldOptions4Title = computed(() => {
|
||||||
let cloneFormField = formField.value.map((item) => {
|
let cloneFormField = formFields.value.map((item) => {
|
||||||
return {
|
return {
|
||||||
label: item.title,
|
label: item.title,
|
||||||
value: item.field
|
value: item.field
|
||||||
|
|
@ -399,7 +382,7 @@ const formFieldOptions4Title = computed(() => {
|
||||||
return cloneFormField
|
return cloneFormField
|
||||||
})
|
})
|
||||||
const formFieldOptions4Summary = computed(() => {
|
const formFieldOptions4Summary = computed(() => {
|
||||||
return formField.value.map((item) => {
|
return formFields.value.map((item) => {
|
||||||
return {
|
return {
|
||||||
label: item.title,
|
label: item.title,
|
||||||
value: item.field
|
value: item.field
|
||||||
|
|
@ -407,6 +390,11 @@ const formFieldOptions4Summary = computed(() => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/** 未解析的表单字段 */
|
||||||
|
const unParsedFormFields = ref<string[]>([])
|
||||||
|
/** 暴露给子组件 HttpRequestSetting 使用 */
|
||||||
|
provide('formFields', unParsedFormFields)
|
||||||
|
|
||||||
/** 兼容以前未配置更多设置的流程 */
|
/** 兼容以前未配置更多设置的流程 */
|
||||||
const initData = () => {
|
const initData = () => {
|
||||||
if (!modelData.value.processIdRule) {
|
if (!modelData.value.processIdRule) {
|
||||||
|
|
@ -445,6 +433,9 @@ const initData = () => {
|
||||||
if (modelData.value.taskAfterTriggerSetting) {
|
if (modelData.value.taskAfterTriggerSetting) {
|
||||||
taskAfterTriggerEnable.value = true
|
taskAfterTriggerEnable.value = true
|
||||||
}
|
}
|
||||||
|
if (modelData.value.allowWithdrawTask) {
|
||||||
|
modelData.value.allowWithdrawTask = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
defineExpose({ initData })
|
defineExpose({ initData })
|
||||||
|
|
||||||
|
|
@ -456,13 +447,15 @@ watch(
|
||||||
const data = await FormApi.getForm(newFormId)
|
const data = await FormApi.getForm(newFormId)
|
||||||
const result: Array<{ field: string; title: string }> = []
|
const result: Array<{ field: string; title: string }> = []
|
||||||
if (data.fields) {
|
if (data.fields) {
|
||||||
|
unParsedFormFields.value = data.fields
|
||||||
data.fields.forEach((fieldStr: string) => {
|
data.fields.forEach((fieldStr: string) => {
|
||||||
parseFormFields(JSON.parse(fieldStr), result)
|
parseFormFields(JSON.parse(fieldStr), result)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
formField.value = result
|
formFields.value = result
|
||||||
} else {
|
} else {
|
||||||
formField.value = []
|
formFields.value = []
|
||||||
|
unParsedFormFields.value = []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
|
|
|
||||||
|
|
@ -77,10 +77,7 @@
|
||||||
|
|
||||||
<!-- 第四步:更多设置 -->
|
<!-- 第四步:更多设置 -->
|
||||||
<div v-show="currentStep === 3" class="mx-auto w-700px">
|
<div v-show="currentStep === 3" class="mx-auto w-700px">
|
||||||
<ExtraSettings
|
<ExtraSettings ref="extraSettingsRef" v-model="formData" />
|
||||||
ref="extraSettingsRef"
|
|
||||||
v-model="formData"
|
|
||||||
:model-form-id="formData.formId"/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -176,7 +173,8 @@ const formData: any = ref({
|
||||||
summarySetting: {
|
summarySetting: {
|
||||||
enable: false,
|
enable: false,
|
||||||
summary: []
|
summary: []
|
||||||
}
|
},
|
||||||
|
allowWithdrawTask: false
|
||||||
})
|
})
|
||||||
|
|
||||||
// 流程数据
|
// 流程数据
|
||||||
|
|
|
||||||
|
|
@ -51,8 +51,10 @@
|
||||||
>
|
>
|
||||||
<div class="ml-10px -mt-15px -mb-35px">
|
<div class="ml-10px -mt-15px -mb-35px">
|
||||||
<ProcessInstanceTimeline
|
<ProcessInstanceTimeline
|
||||||
|
ref="nextAssigneesTimelineRef"
|
||||||
:activity-nodes="nextAssigneesActivityNode"
|
:activity-nodes="nextAssigneesActivityNode"
|
||||||
:show-status-icon="false"
|
:show-status-icon="false"
|
||||||
|
:enable-approve-user-select="true"
|
||||||
@select-user-confirm="selectNextAssigneesConfirm"
|
@select-user-confirm="selectNextAssigneesConfirm"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -571,6 +573,7 @@ const approveFormRef = ref<FormInstance>()
|
||||||
const signRef = ref()
|
const signRef = ref()
|
||||||
const approveSignFormRef = ref()
|
const approveSignFormRef = ref()
|
||||||
const nextAssigneesActivityNode = ref<ProcessInstanceApi.ApprovalNodeInfo[]>([]) // 下一个审批节点信息
|
const nextAssigneesActivityNode = ref<ProcessInstanceApi.ApprovalNodeInfo[]>([]) // 下一个审批节点信息
|
||||||
|
const nextAssigneesTimelineRef = ref() // 下一个节点审批人时间线组件的引用
|
||||||
const approveReasonForm = reactive({
|
const approveReasonForm = reactive({
|
||||||
reason: '',
|
reason: '',
|
||||||
signPicUrl: '',
|
signPicUrl: '',
|
||||||
|
|
@ -717,6 +720,10 @@ const closePopover = (type: string, formRef: FormInstance | undefined) => {
|
||||||
}
|
}
|
||||||
popOverVisible.value[type] = false
|
popOverVisible.value[type] = false
|
||||||
nextAssigneesActivityNode.value = []
|
nextAssigneesActivityNode.value = []
|
||||||
|
// 清理 Timeline 组件中的自定义审批人数据
|
||||||
|
if (nextAssigneesTimelineRef.value) {
|
||||||
|
nextAssigneesTimelineRef.value.batchSetCustomApproveUsers({})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 流程通过时,根据表单变量查询新的流程节点,判断下一个节点类型是否为自选审批人 */
|
/** 流程通过时,根据表单变量查询新的流程节点,判断下一个节点类型是否为自选审批人 */
|
||||||
|
|
@ -729,6 +736,7 @@ const initNextAssigneesFormField = async () => {
|
||||||
processVariablesStr: JSON.stringify(variables)
|
processVariablesStr: JSON.stringify(variables)
|
||||||
})
|
})
|
||||||
if (data && data.length > 0) {
|
if (data && data.length > 0) {
|
||||||
|
const customApproveUsersData: Record<string, any[]> = {} // 用于收集需要设置到 Timeline 组件的自定义审批人数据
|
||||||
data.forEach((node: any) => {
|
data.forEach((node: any) => {
|
||||||
if (
|
if (
|
||||||
// 情况一:当前节点没有审批人,并且是发起人自选
|
// 情况一:当前节点没有审批人,并且是发起人自选
|
||||||
|
|
@ -740,7 +748,18 @@ const initNextAssigneesFormField = async () => {
|
||||||
) {
|
) {
|
||||||
nextAssigneesActivityNode.value.push(node)
|
nextAssigneesActivityNode.value.push(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 如果节点有 candidateUsers,设置到 customApproveUsers 中
|
||||||
|
if (node.candidateUsers && node.candidateUsers.length > 0) {
|
||||||
|
customApproveUsersData[node.id] = node.candidateUsers
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 将 candidateUsers 设置到 Timeline 组件中
|
||||||
|
await nextTick() // 等待下一个 tick,确保 Timeline 组件已经渲染
|
||||||
|
if (nextAssigneesTimelineRef.value && Object.keys(customApproveUsersData).length > 0) {
|
||||||
|
nextAssigneesTimelineRef.value.batchSetCustomApproveUsers(customApproveUsersData)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -803,6 +822,10 @@ const handleAudit = async (pass: boolean, formRef: FormInstance | undefined) =>
|
||||||
await TaskApi.approveTask(data)
|
await TaskApi.approveTask(data)
|
||||||
popOverVisible.value.approve = false
|
popOverVisible.value.approve = false
|
||||||
nextAssigneesActivityNode.value = []
|
nextAssigneesActivityNode.value = []
|
||||||
|
// 清理 Timeline 组件中的自定义审批人数据
|
||||||
|
if (nextAssigneesTimelineRef.value) {
|
||||||
|
nextAssigneesTimelineRef.value.batchSetCustomApproveUsers({})
|
||||||
|
}
|
||||||
message.success('审批通过成功')
|
message.success('审批通过成功')
|
||||||
} else {
|
} else {
|
||||||
// 审批不通过数据
|
// 审批不通过数据
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
>
|
>
|
||||||
<img class="w-full h-full" :src="getApprovalNodeImg(activity.nodeType)" alt="" />
|
<img class="w-full h-full" :src="getApprovalNodeImg(activity.nodeType)" alt="" />
|
||||||
<div
|
<div
|
||||||
v-if="showStatusIcon"
|
v-if="props.showStatusIcon"
|
||||||
class="position-absolute top-17px left-17px rounded-full flex items-center p-1px border-2 border-white border-solid"
|
class="position-absolute top-17px left-17px rounded-full flex items-center p-1px border-2 border-white border-solid"
|
||||||
:style="{ backgroundColor: getApprovalNodeColor(activity.status) }"
|
:style="{ backgroundColor: getApprovalNodeColor(activity.status) }"
|
||||||
>
|
>
|
||||||
|
|
@ -55,13 +55,13 @@
|
||||||
class="flex flex-wrap gap2 items-center"
|
class="flex flex-wrap gap2 items-center"
|
||||||
v-if="
|
v-if="
|
||||||
isEmpty(activity.tasks) &&
|
isEmpty(activity.tasks) &&
|
||||||
isEmpty(activity.candidateUsers) &&
|
((CandidateStrategy.START_USER_SELECT === activity.candidateStrategy &&
|
||||||
(CandidateStrategy.START_USER_SELECT === activity.candidateStrategy ||
|
isEmpty(activity.candidateUsers)) ||
|
||||||
CandidateStrategy.APPROVE_USER_SELECT === activity.candidateStrategy)
|
(props.enableApproveUserSelect &&
|
||||||
|
CandidateStrategy.APPROVE_USER_SELECT === activity.candidateStrategy))
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<!-- && activity.nodeType === NodeType.USER_TASK_NODE -->
|
<!-- && activity.nodeType === NodeType.USER_TASK_NODE -->
|
||||||
|
|
||||||
<el-tooltip content="添加用户" placement="left">
|
<el-tooltip content="添加用户" placement="left">
|
||||||
<el-button
|
<el-button
|
||||||
class="!px-6px"
|
class="!px-6px"
|
||||||
|
|
@ -119,7 +119,7 @@
|
||||||
</template>
|
</template>
|
||||||
<!-- 信息:任务 ICON -->
|
<!-- 信息:任务 ICON -->
|
||||||
<div
|
<div
|
||||||
v-if="showStatusIcon && onlyStatusIconShow.includes(task.status)"
|
v-if="props.showStatusIcon && onlyStatusIconShow.includes(task.status)"
|
||||||
class="position-absolute top-19px left-23px rounded-full flex items-center p-1px border-2 border-white border-solid"
|
class="position-absolute top-19px left-23px rounded-full flex items-center p-1px border-2 border-white border-solid"
|
||||||
:style="{ backgroundColor: statusIconMap2[task.status]?.color }"
|
:style="{ backgroundColor: statusIconMap2[task.status]?.color }"
|
||||||
>
|
>
|
||||||
|
|
@ -165,7 +165,7 @@
|
||||||
|
|
||||||
<!-- 信息:任务 ICON -->
|
<!-- 信息:任务 ICON -->
|
||||||
<div
|
<div
|
||||||
v-if="showStatusIcon"
|
v-if="props.showStatusIcon"
|
||||||
class="position-absolute top-20px left-24px rounded-full flex items-center p-1px border-2 border-white border-solid"
|
class="position-absolute top-20px left-24px rounded-full flex items-center p-1px border-2 border-white border-solid"
|
||||||
:style="{ backgroundColor: statusIconMap2['-1']?.color }"
|
:style="{ backgroundColor: statusIconMap2['-1']?.color }"
|
||||||
>
|
>
|
||||||
|
|
@ -198,13 +198,15 @@ import transactorSvg from '@/assets/svgs/bpm/transactor.svg'
|
||||||
import childProcessSvg from '@/assets/svgs/bpm/child-process.svg'
|
import childProcessSvg from '@/assets/svgs/bpm/child-process.svg'
|
||||||
|
|
||||||
defineOptions({ name: 'BpmProcessInstanceTimeline' })
|
defineOptions({ name: 'BpmProcessInstanceTimeline' })
|
||||||
withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
activityNodes: ProcessInstanceApi.ApprovalNodeInfo[] // 审批节点信息
|
activityNodes: ProcessInstanceApi.ApprovalNodeInfo[] // 审批节点信息
|
||||||
showStatusIcon?: boolean // 是否显示头像右下角状态图标
|
showStatusIcon?: boolean // 是否显示头像右下角状态图标
|
||||||
|
enableApproveUserSelect?: boolean // 是否开启审批人自选功能
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
showStatusIcon: true // 默认值为 true
|
showStatusIcon: true, // 默认值为 true
|
||||||
|
enableApproveUserSelect: false // 默认值为 false
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
const { push } = useRouter() // 路由
|
const { push } = useRouter() // 路由
|
||||||
|
|
@ -341,4 +343,19 @@ const handleChildProcess = (activity: any) => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 设置自定义审批人 */
|
||||||
|
const setCustomApproveUsers = (activityId: string, users: any[]) => {
|
||||||
|
customApproveUsers.value[activityId] = users || []
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 批量设置多个节点的自定义审批人 */
|
||||||
|
const batchSetCustomApproveUsers = (data: Record<string, any[]>) => {
|
||||||
|
Object.keys(data).forEach((activityId) => {
|
||||||
|
customApproveUsers.value[activityId] = data[activityId] || []
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 暴露方法给父组件
|
||||||
|
defineExpose({ setCustomApproveUsers, batchSetCustomApproveUsers })
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -184,8 +184,9 @@
|
||||||
:show-overflow-tooltip="true"
|
:show-overflow-tooltip="true"
|
||||||
/>
|
/>
|
||||||
<el-table-column align="center" label="任务编号" prop="id" :show-overflow-tooltip="true" />
|
<el-table-column align="center" label="任务编号" prop="id" :show-overflow-tooltip="true" />
|
||||||
<el-table-column align="center" label="操作" fixed="right" width="80">
|
<el-table-column align="center" label="操作" fixed="right" width="130">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
|
<el-button link type="warning" @click="handleWithdraw(scope.row)">撤回</el-button>
|
||||||
<el-button link type="primary" @click="handleAudit(scope.row)">历史</el-button>
|
<el-button link type="primary" @click="handleAudit(scope.row)">历史</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
@ -209,6 +210,7 @@ import * as DefinitionApi from '@/api/bpm/definition'
|
||||||
defineOptions({ name: 'BpmDoneTask' })
|
defineOptions({ name: 'BpmDoneTask' })
|
||||||
|
|
||||||
const { push } = useRouter() // 路由
|
const { push } = useRouter() // 路由
|
||||||
|
const message = useMessage()
|
||||||
|
|
||||||
const loading = ref(true) // 列表的加载中
|
const loading = ref(true) // 列表的加载中
|
||||||
const total = ref(0) // 列表的总页数
|
const total = ref(0) // 列表的总页数
|
||||||
|
|
@ -262,6 +264,14 @@ const handleAudit = (row: any) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 测回按钮 */
|
||||||
|
const handleWithdraw = (row: any) => {
|
||||||
|
TaskApi.withdrawTask(row.id).then(() => {
|
||||||
|
message.success('撤回成功')
|
||||||
|
getList()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/** 初始化 **/
|
/** 初始化 **/
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await getList()
|
await getList()
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,34 @@
|
||||||
<el-descriptions-item label="模版发送人名称">
|
<el-descriptions-item label="模版发送人名称">
|
||||||
{{ detailData.templateNickname }}
|
{{ detailData.templateNickname }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="用户信息">
|
<el-descriptions-item label="接收用户">
|
||||||
{{ detailData.toMail }}
|
|
||||||
<span v-if="detailData.userType && detailData.userId">
|
<span v-if="detailData.userType && detailData.userId">
|
||||||
<dict-tag :type="DICT_TYPE.USER_TYPE" :value="detailData.userType" />
|
<dict-tag :type="DICT_TYPE.USER_TYPE" :value="detailData.userType" />
|
||||||
({{ detailData.userId }})
|
({{ detailData.userId }})
|
||||||
</span>
|
</span>
|
||||||
|
<span v-else>无</span>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="接收信息">
|
||||||
|
<div>
|
||||||
|
<div v-if="detailData.toMails && detailData.toMails.length > 0">
|
||||||
|
收件:
|
||||||
|
<span v-for="(mail, index) in detailData.toMails" :key="mail">
|
||||||
|
{{ mail }}<span v-if="index < detailData.toMails.length - 1">、</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div v-if="detailData.ccMails && detailData.ccMails.length > 0">
|
||||||
|
抄送:
|
||||||
|
<span v-for="(mail, index) in detailData.ccMails" :key="mail">
|
||||||
|
{{ mail }}<span v-if="index < detailData.ccMails.length - 1">、</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div v-if="detailData.bccMails && detailData.bccMails.length > 0">
|
||||||
|
密送:
|
||||||
|
<span v-for="(mail, index) in detailData.bccMails" :key="mail">
|
||||||
|
{{ mail }}<span v-if="index < detailData.bccMails.length - 1">、</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="邮件标题">
|
<el-descriptions-item label="邮件标题">
|
||||||
{{ detailData.templateTitle }}
|
{{ detailData.templateTitle }}
|
||||||
|
|
@ -58,7 +80,7 @@ defineOptions({ name: 'SystemMailLogDetail' })
|
||||||
const dialogVisible = ref(false) // 弹窗的是否展示
|
const dialogVisible = ref(false) // 弹窗的是否展示
|
||||||
const detailLoading = ref(false) // 表单的加载中
|
const detailLoading = ref(false) // 表单的加载中
|
||||||
const detailData = ref() // 详情数据
|
const detailData = ref() // 详情数据
|
||||||
const accountList = ref([]) // 邮箱账号列表
|
const accountList = ref<MailAccountApi.MailAccountVO[]>([]) // 邮箱账号列表
|
||||||
|
|
||||||
/** 打开弹窗 */
|
/** 打开弹窗 */
|
||||||
const open = async (data: MailLogApi.MailLogVO) => {
|
const open = async (data: MailLogApi.MailLogVO) => {
|
||||||
|
|
|
||||||
|
|
@ -119,12 +119,36 @@
|
||||||
width="180"
|
width="180"
|
||||||
:formatter="dateFormatter"
|
:formatter="dateFormatter"
|
||||||
/>
|
/>
|
||||||
<el-table-column label="接收邮箱" align="center" prop="toMail" width="200">
|
<el-table-column label="接收用户" align="center" width="150">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<div>{{ scope.row.toMail }}</div>
|
|
||||||
<div v-if="scope.row.userType && scope.row.userId">
|
<div v-if="scope.row.userType && scope.row.userId">
|
||||||
<dict-tag :type="DICT_TYPE.USER_TYPE" :value="scope.row.userType" />
|
<dict-tag :type="DICT_TYPE.USER_TYPE" :value="scope.row.userType" />
|
||||||
{{ '(' + scope.row.userId + ')' }}
|
<div>{{ '(' + scope.row.userId + ')' }}</div>
|
||||||
|
</div>
|
||||||
|
<div v-else>-</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="接收信息" align="center" width="300">
|
||||||
|
<template #default="scope">
|
||||||
|
<div class="text-left">
|
||||||
|
<div v-if="scope.row.toMails && scope.row.toMails.length > 0">
|
||||||
|
收件:
|
||||||
|
<span v-for="(mail, index) in scope.row.toMails" :key="mail">
|
||||||
|
{{ mail }}<span v-if="index < scope.row.toMails.length - 1">、</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div v-if="scope.row.ccMails && scope.row.ccMails.length > 0">
|
||||||
|
抄送:
|
||||||
|
<span v-for="(mail, index) in scope.row.ccMails" :key="mail">
|
||||||
|
{{ mail }}<span v-if="index < scope.row.ccMails.length - 1">、</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div v-if="scope.row.bccMails && scope.row.bccMails.length > 0">
|
||||||
|
密送:
|
||||||
|
<span v-for="(mail, index) in scope.row.bccMails" :key="mail">
|
||||||
|
{{ mail }}<span v-if="index < scope.row.bccMails.length - 1">、</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
@ -185,15 +209,15 @@ const queryParams = reactive({
|
||||||
pageNo: 1,
|
pageNo: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
toMail: '',
|
toMail: '',
|
||||||
accountId: null,
|
accountId: undefined,
|
||||||
templateId: null,
|
templateId: undefined,
|
||||||
sendStatus: null,
|
sendStatus: undefined,
|
||||||
userId: null,
|
userId: undefined,
|
||||||
userType: null,
|
userType: undefined,
|
||||||
sendTime: []
|
sendTime: []
|
||||||
})
|
})
|
||||||
const exportLoading = ref(false) // 导出的加载中
|
const exportLoading = ref(false) // 导出的加载中
|
||||||
const accountList = ref([]) // 邮箱账号列表
|
const accountList = ref<MailAccountApi.MailAccountVO[]>([]) // 邮箱账号列表
|
||||||
|
|
||||||
/** 查询列表 */
|
/** 查询列表 */
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,26 @@
|
||||||
<el-form-item label="模板内容" prop="content">
|
<el-form-item label="模板内容" prop="content">
|
||||||
<Editor :model-value="formData.content" height="150px" readonly />
|
<Editor :model-value="formData.content" height="150px" readonly />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="收件邮箱" prop="mail">
|
<el-form-item label="收件邮箱" prop="toMails">
|
||||||
<el-input v-model="formData.mail" placeholder="请输入收件邮箱" />
|
<el-input-tag
|
||||||
|
v-model="formData.toMails"
|
||||||
|
placeholder="请输入收件邮箱,多个邮箱用回车分隔"
|
||||||
|
class="!w-full"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="抄送邮箱" prop="ccMails">
|
||||||
|
<el-input-tag
|
||||||
|
v-model="formData.ccMails"
|
||||||
|
placeholder="请输入抄送邮箱,多个邮箱用回车分隔"
|
||||||
|
class="!w-full"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="密送邮箱" prop="bccMails">
|
||||||
|
<el-input-tag
|
||||||
|
v-model="formData.bccMails"
|
||||||
|
placeholder="请输入密送邮箱,多个邮箱用回车分隔"
|
||||||
|
class="!w-full"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
v-for="param in formData.params"
|
v-for="param in formData.params"
|
||||||
|
|
@ -43,12 +61,13 @@ const formLoading = ref(false) // 表单的加载中:1)修改时的数据加
|
||||||
const formData = ref({
|
const formData = ref({
|
||||||
content: '',
|
content: '',
|
||||||
params: {},
|
params: {},
|
||||||
mail: '',
|
toMails: [],
|
||||||
|
ccMails: [],
|
||||||
|
bccMails: [],
|
||||||
templateCode: '',
|
templateCode: '',
|
||||||
templateParams: new Map()
|
templateParams: new Map()
|
||||||
})
|
})
|
||||||
const formRules = reactive({
|
const formRules = reactive({
|
||||||
mail: [{ required: true, message: '邮箱不能为空', trigger: 'blur' }],
|
|
||||||
templateCode: [{ required: true, message: '模版编号不能为空', trigger: 'blur' }],
|
templateCode: [{ required: true, message: '模版编号不能为空', trigger: 'blur' }],
|
||||||
templateParams: {}
|
templateParams: {}
|
||||||
})
|
})
|
||||||
|
|
@ -105,7 +124,9 @@ const resetForm = () => {
|
||||||
formData.value = {
|
formData.value = {
|
||||||
content: '',
|
content: '',
|
||||||
params: {},
|
params: {},
|
||||||
mail: '',
|
toMails: [],
|
||||||
|
ccMails: [],
|
||||||
|
bccMails: [],
|
||||||
templateCode: '',
|
templateCode: '',
|
||||||
templateParams: new Map()
|
templateParams: new Map()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue