diff --git a/.vscode/settings.json b/.vscode/settings.json index cc1dae50..74ab52a7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -62,16 +62,16 @@ "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[typescript]": { - "editor.defaultFormatter": "rvest.vs-code-prettier-eslint" + "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[typescriptreact]": { - "editor.defaultFormatter": "rvest.vs-code-prettier-eslint" + "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[html]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[css]": { - "editor.defaultFormatter": "rvest.vs-code-prettier-eslint" + "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[less]": { "editor.defaultFormatter": "esbenp.prettier-vscode" @@ -86,8 +86,9 @@ "source.fixAll.eslint": "explicit", "source.fixAll.stylelint": "explicit" }, + "editor.formatOnSave": true, "[vue]": { - "editor.defaultFormatter": "octref.vetur" + "editor.defaultFormatter": "esbenp.prettier-vscode" }, "i18n-ally.localesPaths": ["src/locales"], "i18n-ally.keystyle": "nested", diff --git a/src/components/bpmnProcessDesigner/package/penal/PropertiesPanel.vue b/src/components/bpmnProcessDesigner/package/penal/PropertiesPanel.vue index ff08dd33..f375f90e 100644 --- a/src/components/bpmnProcessDesigner/package/penal/PropertiesPanel.vue +++ b/src/components/bpmnProcessDesigner/package/penal/PropertiesPanel.vue @@ -68,6 +68,11 @@ :business-object="elementBusinessObject" /> + + + 时间事件 + + @@ -83,6 +88,8 @@ import ElementProperties from './properties/ElementProperties.vue' // import ElementForm from './form/ElementForm.vue' import UserTaskListeners from './listeners/UserTaskListeners.vue' import { getTaskCollapseItemName, isTaskCollapseItemShow } from './task/data' +import TimeEventConfig from "./time-event-config/TimeEventConfig.vue" +import { ref, computed, watch, onMounted } from 'vue' defineOptions({ name: 'MyPropertiesPanel' }) @@ -121,6 +128,8 @@ const formVisible = ref(false) // 表单配置 const bpmnElement = ref() const isReady = ref(false) +const type = ref('time') +const condition = ref('') provide('prefix', props.prefix) provide('width', props.width) @@ -255,4 +264,54 @@ watch( activeTab.value = 'base' } ) + +function updateNode() { + const moddle = window.bpmnInstances?.moddle + const modeling = window.bpmnInstances?.modeling + const elementRegistry = window.bpmnInstances?.elementRegistry + if (!moddle || !modeling || !elementRegistry) return + + const element = elementRegistry.get(props.businessObject.id) + if (!element) return + + let timerDef = moddle.create('bpmn:TimerEventDefinition', {}) + if (type.value === 'time') { + timerDef.timeDate = moddle.create('bpmn:FormalExpression', { body: condition.value }) + } else if (type.value === 'duration') { + timerDef.timeDuration = moddle.create('bpmn:FormalExpression', { body: condition.value }) + } else if (type.value === 'cycle') { + timerDef.timeCycle = moddle.create('bpmn:FormalExpression', { body: condition.value }) + } + + modeling.updateModdleProperties( + element, + element.businessObject, + { + eventDefinitions: [timerDef] + } + ) + + console.log('当前eventDefinitions:', element.businessObject.eventDefinitions) +} + +// 初始化和监听 +function syncFromBusinessObject() { + if (props.businessObject) { + const timerDef = (props.businessObject.eventDefinitions || [])[0] + if (timerDef) { + if (timerDef.timeDate) { + type.value = 'time' + condition.value = timerDef.timeDate.body + } else if (timerDef.timeDuration) { + type.value = 'duration' + condition.value = timerDef.timeDuration.body + } else if (timerDef.timeCycle) { + type.value = 'cycle' + condition.value = timerDef.timeCycle.body + } + } + } +} +onMounted(syncFromBusinessObject) +watch(() => props.businessObject, syncFromBusinessObject, { deep: true }) diff --git a/src/components/bpmnProcessDesigner/package/penal/time-event-config/CycleConfig.vue b/src/components/bpmnProcessDesigner/package/penal/time-event-config/CycleConfig.vue new file mode 100644 index 00000000..52a57ef1 --- /dev/null +++ b/src/components/bpmnProcessDesigner/package/penal/time-event-config/CycleConfig.vue @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + 每{{f.label}} + 从 到 之间每{{f.label}} + 从第 开始每 {{f.label}} + 指定 + + + + + {{pad(n-1)}} + + + + + + + + + + 循环次数: + 日期时间: + 当前时长: + + 秒:{{s}}自定义 + 分:{{m}}自定义 + 小时:{{h}}自定义 + 天:{{d}}自定义 + 月:{{mo}}自定义 + 年:{{y}}自定义 + + + + + \ No newline at end of file diff --git a/src/components/bpmnProcessDesigner/package/penal/time-event-config/DurationConfig.vue b/src/components/bpmnProcessDesigner/package/penal/time-event-config/DurationConfig.vue new file mode 100644 index 00000000..75688b34 --- /dev/null +++ b/src/components/bpmnProcessDesigner/package/penal/time-event-config/DurationConfig.vue @@ -0,0 +1,66 @@ + + + 当前选择: + + {{ unit.label }}: + + {{ val }} + + + + + + + diff --git a/src/components/bpmnProcessDesigner/package/penal/time-event-config/TimeEventConfig.vue b/src/components/bpmnProcessDesigner/package/penal/time-event-config/TimeEventConfig.vue new file mode 100644 index 00000000..8321ed40 --- /dev/null +++ b/src/components/bpmnProcessDesigner/package/penal/time-event-config/TimeEventConfig.vue @@ -0,0 +1,282 @@ + + + + 类型: + + 时间 + 持续 + 循环 + + + + + 条件: + + + + + + + + + + + + + + + + + + + + + + + + + 取消 + 确定 + + + + + + + 取消 + 确定 + + + + + + + 取消 + 确定 + + + + + + + 关闭 + + + + + + + + diff --git a/src/store/modules/app.ts b/src/store/modules/app.ts index e3d6a56f..4a2ca9ae 100644 --- a/src/store/modules/app.ts +++ b/src/store/modules/app.ts @@ -1,11 +1,12 @@ -import { defineStore } from 'pinia' -import { store } from '../index' -import { humpToUnderline, setCssVar } from '@/utils' -import { ElMessage } from 'element-plus' import { CACHE_KEY, useCache } from '@/hooks/web/useCache' import { ElementPlusSize } from '@/types/elementPlus' import { LayoutType } from '@/types/layout' import { ThemeTypes } from '@/types/theme' +import { humpToUnderline, setCssVar } from '@/utils' +import { getCssColorVariable, hexToRGB, mix } from '@/utils/color' +import { ElMessage } from 'element-plus' +import { defineStore } from 'pinia' +import { store } from '../index' const { wsCache } = useCache() @@ -183,6 +184,40 @@ export const useAppStore = defineStore('app', { } }, actions: { + setPrimaryLight() { + if (this.theme.elColorPrimary) { + const elColorPrimary = this.theme.elColorPrimary + const color = this.isDark ? '#000000' : '#ffffff' + const lightList = [3, 5, 7, 8, 9] + lightList.forEach((v) => { + setCssVar(`--el-color-primary-light-${v}`, mix(color, elColorPrimary, v / 10)) + }) + setCssVar(`--el-color-primary-dark-2`, mix(color, elColorPrimary, 0.2)) + + this.setAllColorRgbVars() + } + }, + + // 处理element自带的主题色和辅助色的-rgb切换主题变化,如:--el-color-primary-rgb + setAllColorRgbVars() { + // 需要处理的颜色类型列表 + const colorTypes = ['primary', 'success', 'warning', 'danger', 'error', 'info'] + + colorTypes.forEach((type) => { + // 获取当前颜色值 + const colorValue = getCssColorVariable(`--el-color-${type}`) + if (colorValue) { + // 转换为rgba并提取RGB部分 + const rgbaString = hexToRGB(colorValue, 1) + const rgbValues = rgbaString.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/i) + if (rgbValues) { + const [, r, g, b] = rgbValues + // 设置对应的RGB变量 + setCssVar(`--el-color-${type}-rgb`, `${r}, ${g}, ${b}`) + } + } + }) + }, setBreadcrumb(breadcrumb: boolean) { this.breadcrumb = breadcrumb }, @@ -256,6 +291,7 @@ export const useAppStore = defineStore('app', { document.documentElement.classList.remove('dark') } wsCache.set(CACHE_KEY.IS_DARK, this.isDark) + this.setPrimaryLight() }, setCurrentSize(currentSize: ElementPlusSize) { this.currentSize = currentSize @@ -272,6 +308,7 @@ export const useAppStore = defineStore('app', { for (const key in this.theme) { setCssVar(`--${humpToUnderline(key)}`, this.theme[key]) } + this.setPrimaryLight() }, setFooter(footer: boolean) { this.footer = footer diff --git a/src/utils/color.ts b/src/utils/color.ts index 13424e57..943be97e 100644 --- a/src/utils/color.ts +++ b/src/utils/color.ts @@ -172,3 +172,46 @@ export const PREDEFINE_COLORS = [ '#1f73c3', '#711f57' ] + + +/** + * Mixes two colors. + * + * @param {string} color1 - The first color, should be a 6-digit hexadecimal color code starting with `#`. + * @param {string} color2 - The second color, should be a 6-digit hexadecimal color code starting with `#`. + * @param {number} [weight=0.5] - The weight of color1 in the mix, should be a number between 0 and 1, where 0 represents 100% of color2, and 1 represents 100% of color1. + * @returns {string} The mixed color, a 6-digit hexadecimal color code starting with `#`. + */ +export const mix = (color1: string, color2: string, weight: number = 0.5): string => { + let color = '#' + for (let i = 0; i <= 2; i++) { + const c1 = parseInt(color1.substring(1 + i * 2, 3 + i * 2), 16) + const c2 = parseInt(color2.substring(1 + i * 2, 3 + i * 2), 16) + const c = Math.round(c1 * weight + c2 * (1 - weight)) + color += c.toString(16).padStart(2, '0') + } + return color +} + +/** + * getCssColorVariable + * @description 获取css变量的颜色值 + * @param colorVariable css变量名 + * @param opacity 透明度 + * @returns {string} 颜色值 + * @example getCssColorVariable('--el-color-primary', 0.5) + * @example getCssColorVariable('--el-color-primary') + * @example getCssColorVariable() + */ +export const getCssColorVariable = ( + colorVariable: string = '--el-color-primary', + opacity?: number +) => { + const colorValue = getComputedStyle(document.documentElement) + .getPropertyValue(colorVariable) + .trim() + if (colorValue) { + return opacity ? hexToRGB(colorValue, opacity) : colorValue + } + return '' +}