Merge branch 'master' of https://gitee.com/yudaocode/yudao-ui-admin-vue3 into feature/bpm

This commit is contained in:
YunaiV
2024-08-10 19:30:50 +08:00
191 changed files with 15212 additions and 8288 deletions

View File

@ -54,7 +54,7 @@ const currentLocale = computed(() => localeStore.currentLocale)
<ElConfigProvider
:namespace="variables.elNamespace"
:locale="currentLocale.elLocale"
:message="{ max: 1 }"
:message="{ max: 5 }"
:size="size"
>
<slot></slot>

View File

@ -10,12 +10,13 @@ const prefixCls = getPrefixCls('content-wrap')
defineProps({
title: propTypes.string.def(''),
message: propTypes.string.def('')
message: propTypes.string.def(''),
bodyStyle: propTypes.object.def({ padding: '20px' })
})
</script>
<template>
<ElCard :class="[prefixCls, 'mb-15px']" shadow="never">
<ElCard :body-style="bodyStyle" :class="[prefixCls, 'mb-15px']" shadow="never">
<template v-if="title" #header>
<div class="flex items-center">
<span class="text-16px font-700">{{ title }}</span>
@ -30,8 +31,6 @@ defineProps({
</div>
</div>
</template>
<div>
<slot></slot>
</div>
<slot></slot>
</ElCard>
</template>

View File

@ -1,8 +1,9 @@
<script lang="tsx">
import { defineComponent, PropType, ref } from 'vue'
import { defineComponent, PropType, computed } from 'vue'
import { isHexColor } from '@/utils/color'
import { ElTag } from 'element-plus'
import { DictDataType, getDictOptions } from '@/utils/dict'
import { isArray, isString, isNumber } from '@/utils/is'
export default defineComponent({
name: 'DictTag',
@ -12,49 +13,78 @@ export default defineComponent({
required: true
},
value: {
type: [String, Number, Boolean] as PropType<string | number | boolean>,
type: [String, Number, Boolean, Array],
required: true
},
// 字符串分隔符 只有当 props.value 传入值为字符串时有效
separator: {
type: String as PropType<string>,
default: ','
},
// 每个 tag 之间的间隔,默认为 5px参考的 el-row 的 gutter
gutter: {
type: String as PropType<string>,
default: '5px'
}
},
setup(props) {
const dictData = ref<DictDataType>()
const getDictObj = (dictType: string, value: string) => {
const dictOptions = getDictOptions(dictType)
dictOptions.forEach((dict: DictDataType) => {
if (dict.value === value) {
if (dict.colorType + '' === 'primary' || dict.colorType + '' === 'default') {
dict.colorType = ''
}
dictData.value = dict
}
})
}
const rederDictTag = () => {
const valueArr: any = computed(() => {
// 1.是Number类型的情况
if (isNumber(props.value)) {
return [String(props.value)]
}
// 2.是字符串(进一步判断是否有包含分隔符号 -> props.sepSymbol
else if (isString(props.value)) {
return props.value.split(props.separator)
}
// 3.数组
else if (isArray(props.value)) {
return props.value.map(String)
}
return []
})
const renderDictTag = () => {
if (!props.type) {
return null
}
// 解决自定义字典标签值为零时标签不渲染的问题
if (props.value === undefined || props.value === null) {
if (props.value === undefined || props.value === null || props.value === '') {
return null
}
getDictObj(props.type, props.value.toString())
// 添加标签的文字颜色为白色,解决自定义背景颜色时标签文字看不清的问题
const dictOptions = getDictOptions(props.type)
return (
<ElTag
style={dictData.value?.cssClass ? 'color: #fff' : ''}
type={dictData.value?.colorType}
color={
dictData.value?.cssClass && isHexColor(dictData.value?.cssClass)
? dictData.value?.cssClass
: ''
}
disableTransitions={true}
<div
class="dict-tag"
style={{
display: 'flex',
gap: props.gutter,
justifyContent: 'center',
alignItems: 'center'
}}
>
{dictData.value?.label}
</ElTag>
{dictOptions.map((dict: DictDataType) => {
if (valueArr.value.includes(dict.value)) {
if (dict.colorType + '' === 'primary' || dict.colorType + '' === 'default') {
dict.colorType = ''
}
return (
// 添加标签的文字颜色为白色,解决自定义背景颜色时标签文字看不清的问题
<ElTag
style={dict?.cssClass ? 'color: #fff' : ''}
type={dict?.colorType}
color={dict?.cssClass && isHexColor(dict?.cssClass) ? dict?.cssClass : ''}
disableTransitions={true}
>
{dict?.label}
</ElTag>
)
}
})}
</div>
)
}
return () => rederDictTag()
return () => renderDictTag()
}
})
</script>

View File

@ -95,6 +95,7 @@ const handleCloneComponent = (component: DiyComponent<any>) => {
.editor-left {
z-index: 1;
flex-shrink: 0;
user-select: none;
box-shadow: 8px 0 8px -8px rgb(0 0 0 / 12%);
:deep(.el-collapse) {

View File

@ -96,11 +96,6 @@ const editorConfig = computed((): IEditorConfig => {
// 选择文件时的类型限制,默认为 ['image/*'] 。如不想限制,则设置为 []
allowedFileTypes: ['image/*'],
// 自定义上传参数,例如传递验证的 token 等。参数会被添加到 formData 中,一起上传到服务端。
meta: { updateSupport: 0 },
// 将 meta 拼接到 url 参数中,默认 false
metaWithUrl: true,
// 自定义增加 http header
headers: {
Accept: '*',
@ -108,9 +103,6 @@ const editorConfig = computed((): IEditorConfig => {
'tenant-id': getTenantId()
},
// 跨域是否传递 cookie ,默认为 false
withCredentials: true,
// 超时时间,默认为 10 秒
timeout: 5 * 1000, // 5 秒
@ -119,7 +111,7 @@ const editorConfig = computed((): IEditorConfig => {
// 上传之前触发
onBeforeUpload(file: File) {
console.log(file)
// console.log(file)
return file
},
// 上传进度的回调函数
@ -142,6 +134,54 @@ const editorConfig = computed((): IEditorConfig => {
customInsert(res: any, insertFn: InsertFnType) {
insertFn(res.data, 'image', res.data)
}
},
['uploadVideo']: {
server: import.meta.env.VITE_UPLOAD_URL,
// 单个文件的最大体积限制,默认为 10M
maxFileSize: 10 * 1024 * 1024,
// 最多可上传几个文件,默认为 100
maxNumberOfFiles: 10,
// 选择文件时的类型限制,默认为 ['video/*'] 。如不想限制,则设置为 []
allowedFileTypes: ['video/*'],
// 自定义增加 http header
headers: {
Accept: '*',
Authorization: 'Bearer ' + getAccessToken(),
'tenant-id': getTenantId()
},
// 超时时间,默认为 30 秒
timeout: 15 * 1000, // 15 秒
// form-data fieldName后端接口参数名称默认值wangeditor-uploaded-image
fieldName: 'file',
// 上传之前触发
onBeforeUpload(file: File) {
// console.log(file)
return file
},
// 上传进度的回调函数
onProgress(progress: number) {
// progress 是 0-100 的数字
console.log('progress', progress)
},
onSuccess(file: File, res: any) {
console.log('onSuccess', file, res)
},
onFailed(file: File, res: any) {
alert(res.message)
console.log('onFailed', file, res)
},
onError(file: File, err: any, res: any) {
alert(err.message)
console.error('onError', file, err, res)
},
// 自定义插入图片
customInsert(res: any, insertFn: InsertFnType) {
insertFn(res.data, 'mp4', res.data)
}
}
},
uploadImgShowBase64: true

View File

@ -1,43 +1,12 @@
<template>
<div ref="contentRef" class="markdown-view" v-html="contentHtml"></div>
<div ref="contentRef" class="markdown-view" v-html="renderedMarkdown"></div>
</template>
<script setup lang="ts">
import {useClipboard} from "@vueuse/core";
import {marked} from 'marked'
import { useClipboard } from '@vueuse/core'
import MarkdownIt from 'markdown-it'
import 'highlight.js/styles/vs2015.min.css'
import hljs from 'highlight.js'
import {ref} from "vue";
const {copy} = useClipboard() // 初始化 copy 到粘贴板
const contentRef = ref()
// 代码高亮https://highlightjs.org/
// 转换 markdownmarked
// marked 渲染器
const renderer = {
code(code, language, c) {
let highlightHtml
try {
highlightHtml = hljs.highlight(code, {language: language, ignoreIllegals: true}).value
} catch (e) {
// skip
}
const copyHtml = `<div id="copy" data-copy='${code}' style="position: absolute; right: 10px; top: 5px; color: #fff;cursor: pointer;">复制</div>`
return `<pre style="position: relative;">${copyHtml}<code class="hljs">${highlightHtml}</code></pre>`
}
}
// 配置 marked
marked.use({
renderer: renderer
})
// 渲染的html内容
const contentHtml = ref<any>()
// 定义组件属性
const props = defineProps({
@ -47,39 +16,39 @@ const props = defineProps({
}
})
// 将 props 变为引用类型
const { content } = toRefs(props)
const message = useMessage() // 消息弹窗
const { copy } = useClipboard() // 初始化 copy 到粘贴板
const contentRef = ref()
// 监听 content 变化
watch(content, async (newValue, oldValue) => {
await renderMarkdown(newValue);
const md = new MarkdownIt({
highlight: function (str, lang) {
if (lang && hljs.getLanguage(lang)) {
try {
const copyHtml = `<div id="copy" data-copy='${str}' style="position: absolute; right: 10px; top: 5px; color: #fff;cursor: pointer;">复制</div>`
return `<pre style="position: relative;">${copyHtml}<code class="hljs">${hljs.highlight(lang, str, true).value}</code></pre>`
} catch (__) {}
}
return ``
}
})
// 渲染 markdown
const renderMarkdown = async (content: string) => {
contentHtml.value = await marked(content)
}
/** 渲染 markdown */
const renderedMarkdown = computed(() => {
return md.render(props.content)
})
// 组件挂在时
onMounted(async () => {
// 解析转换 markdown
await renderMarkdown(props.content as string);
//
/** 初始化 **/
onMounted(async () => {
// 添加 copy 监听
contentRef.value.addEventListener('click', (e: any) => {
console.log(e)
if (e.target.id === 'copy') {
copy(e.target?.dataset?.copy)
ElMessage({
message: '复制成功!',
type: 'success'
})
message.success('复制成功!')
}
})
})
</script>
<style lang="scss">
.markdown-view {
font-family: PingFang SC;

View File

@ -32,6 +32,7 @@
格式为 <b style="color: #f56c6c">{{ fileType.join('/') }}</b> 的文件
</div>
</template>
<!-- TODO @puhui9991表单展示的时候位置会偏掉已发微信2disable 的时候应该把删除按钮也隐藏掉 -->
<template #file="row">
<div class="flex items-center">
<span>{{ row.file.name }}</span>

View File

@ -129,7 +129,7 @@ const updateFlowType = (flowType) => {
conditionExpression: null
})
bpmnInstances().modeling.updateProperties(toRaw(bpmnElementSource.value), {
default: bpmnElement.value
default: toRaw(bpmnElement.value)
})
return
}

View File

@ -43,9 +43,6 @@ import { CommonStatusEnum } from '@/utils/constants'
/** BPM 流程 表单 */
defineOptions({ name: 'ProcessListenerDialog' })
const { t } = useI18n() // 国际化
const message = useMessage() // 消息弹窗
const dialogVisible = ref(false) // 弹窗的是否展示
const loading = ref(true) // 列表的加载中
const list = ref<ProcessListenerVO[]>([]) // 列表的数据
@ -53,17 +50,23 @@ const total = ref(0) // 列表的总页数
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
type: undefined,
type: '',
status: CommonStatusEnum.ENABLE
})
/** 打开弹窗 */
const open = async (type: string) => {
queryParams.pageNo = 1
queryParams.type = type
getList()
dialogVisible.value = true
}
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
queryParams.pageNo = 1
queryParams.type = type
const data = await ProcessListenerApi.getProcessListenerPage(queryParams)
list.value = data.list
total.value = data.total
@ -71,7 +74,6 @@ const open = async (type: string) => {
loading.value = false
}
}
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
/** 提交表单 */
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调

View File

@ -28,9 +28,6 @@ import { ProcessExpressionApi, ProcessExpressionVO } from '@/api/bpm/processExpr
/** BPM 流程 表单 */
defineOptions({ name: 'ProcessExpressionDialog' })
const { t } = useI18n() // 国际化
const message = useMessage() // 消息弹窗
const dialogVisible = ref(false) // 弹窗的是否展示
const loading = ref(true) // 列表的加载中
const list = ref<ProcessExpressionVO[]>([]) // 列表的数据
@ -38,17 +35,23 @@ const total = ref(0) // 列表的总页数
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
type: undefined,
type: '',
status: CommonStatusEnum.ENABLE
})
/** 打开弹窗 */
const open = async (type: string) => {
const open = (type: string) => {
queryParams.pageNo = 1
queryParams.type = type
getList()
dialogVisible.value = true
}
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
queryParams.pageNo = 1
queryParams.type = type
const data = await ProcessExpressionApi.getProcessExpressionPage(queryParams)
list.value = data.list
total.value = data.total
@ -56,7 +59,6 @@ const open = async (type: string) => {
loading.value = false
}
}
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
/** 提交表单 */
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调

View File

@ -135,6 +135,7 @@ import * as PostApi from '@/api/system/post'
import * as UserApi from '@/api/system/user'
import * as UserGroupApi from '@/api/bpm/userGroup'
import ProcessExpressionDialog from './ProcessExpressionDialog.vue'
import { ProcessExpressionVO } from '@/api/bpm/processExpression'
defineOptions({ name: 'UserTask' })
const props = defineProps({
@ -197,8 +198,9 @@ const processExpressionDialogRef = ref()
const openProcessExpressionDialog = async () => {
processExpressionDialogRef.value.open()
}
const selectProcessExpression = (expression) => {
const selectProcessExpression = (expression: ProcessExpressionVO) => {
userTaskForm.value.candidateParam = [expression.expression]
updateElementTask()
}
watch(