Merge remote-tracking branch 'yudao/dev' into dev
This commit is contained in:
1225
apps/web-antd/src/components/cron-tab/cron-tab.vue
Normal file
1225
apps/web-antd/src/components/cron-tab/cron-tab.vue
Normal file
File diff suppressed because it is too large
Load Diff
1
apps/web-antd/src/components/cron-tab/index.ts
Normal file
1
apps/web-antd/src/components/cron-tab/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default as CronTab } from './cron-tab.vue';
|
||||
@@ -75,7 +75,7 @@ defineExpose({
|
||||
<div class="inline-block text-center" :style="getStyle">
|
||||
<!-- 图片包装器 -->
|
||||
<div
|
||||
class="group relative cursor-pointer overflow-hidden rounded-full border border-gray-200 bg-white"
|
||||
class="bg-card group relative cursor-pointer overflow-hidden rounded-full border border-gray-200"
|
||||
:style="getImageWrapperStyle"
|
||||
@click="openModal"
|
||||
>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
|
||||
import { isValidColor, TinyColor } from '@vben/utils';
|
||||
|
||||
import { Tag } from 'ant-design-vue';
|
||||
|
||||
// import { isHexColor } from '@/utils/color' // TODO @芋艿:【可优化】增加 cssClass 的处理 https://gitee.com/yudaocode/yudao-ui-admin-vben/blob/v2.4.1/src/components/DictTag/src/DictTag.vue#L60
|
||||
import { getDictObj } from '#/utils';
|
||||
|
||||
interface DictTagProps {
|
||||
@@ -23,11 +24,6 @@ interface DictTagProps {
|
||||
|
||||
const props = defineProps<DictTagProps>();
|
||||
|
||||
function isHexColor(color: string) {
|
||||
const reg = /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i;
|
||||
return reg.test(color);
|
||||
}
|
||||
|
||||
/** 获取字典标签 */
|
||||
const dictTag = computed(() => {
|
||||
// 校验参数有效性
|
||||
@@ -63,9 +59,14 @@ const dictTag = computed(() => {
|
||||
}
|
||||
}
|
||||
|
||||
if (isValidColor(dict.cssClass)) {
|
||||
colorType = new TinyColor(dict.cssClass).toHexString();
|
||||
}
|
||||
|
||||
return {
|
||||
label: dict.label || '',
|
||||
colorType,
|
||||
cssClass: dict.cssClass,
|
||||
};
|
||||
});
|
||||
</script>
|
||||
@@ -73,13 +74,7 @@ const dictTag = computed(() => {
|
||||
<template>
|
||||
<Tag
|
||||
v-if="dictTag"
|
||||
:color="
|
||||
dictTag.colorType
|
||||
? dictTag.colorType
|
||||
: dictTag.cssClass && isHexColor(dictTag.cssClass)
|
||||
? dictTag.cssClass
|
||||
: ''
|
||||
"
|
||||
:color="dictTag.colorType ? dictTag.colorType : dictTag.cssClass"
|
||||
>
|
||||
{{ dictTag.label }}
|
||||
</Tag>
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
SelectOption,
|
||||
} from 'ant-design-vue';
|
||||
|
||||
import { getDictObj, getIntDictOptions, getStrDictOptions } from '#/utils';
|
||||
import { getDictOptions } from '#/utils';
|
||||
|
||||
defineOptions({ name: 'DictSelect' });
|
||||
|
||||
@@ -25,17 +25,16 @@ const props = withDefaults(defineProps<DictSelectProps>(), {
|
||||
const attrs = useAttrs();
|
||||
|
||||
// 获得字典配置
|
||||
// TODO @dhb:可以使用 getDictOptions 替代么?
|
||||
const getDictOptions = computed(() => {
|
||||
const getDictOption = computed(() => {
|
||||
switch (props.valueType) {
|
||||
case 'bool': {
|
||||
return getDictObj(props.dictType, 'bool');
|
||||
return getDictOptions(props.dictType, 'boolean');
|
||||
}
|
||||
case 'int': {
|
||||
return getIntDictOptions(props.dictType);
|
||||
return getDictOptions(props.dictType, 'number');
|
||||
}
|
||||
case 'str': {
|
||||
return getStrDictOptions(props.dictType);
|
||||
return getDictOptions(props.dictType, 'string');
|
||||
}
|
||||
default: {
|
||||
return [];
|
||||
@@ -47,7 +46,7 @@ const getDictOptions = computed(() => {
|
||||
<template>
|
||||
<Select v-if="selectType === 'select'" class="w-full" v-bind="attrs">
|
||||
<SelectOption
|
||||
v-for="(dict, index) in getDictOptions"
|
||||
v-for="(dict, index) in getDictOption"
|
||||
:key="index"
|
||||
:value="dict.value"
|
||||
>
|
||||
@@ -56,7 +55,7 @@ const getDictOptions = computed(() => {
|
||||
</Select>
|
||||
<RadioGroup v-if="selectType === 'radio'" class="w-full" v-bind="attrs">
|
||||
<Radio
|
||||
v-for="(dict, index) in getDictOptions"
|
||||
v-for="(dict, index) in getDictOption"
|
||||
:key="index"
|
||||
:value="dict.value"
|
||||
>
|
||||
@@ -65,7 +64,7 @@ const getDictOptions = computed(() => {
|
||||
</RadioGroup>
|
||||
<CheckboxGroup v-if="selectType === 'checkbox'" class="w-full" v-bind="attrs">
|
||||
<Checkbox
|
||||
v-for="(dict, index) in getDictOptions"
|
||||
v-for="(dict, index) in getDictOption"
|
||||
:key="index"
|
||||
:value="dict.value"
|
||||
>
|
||||
|
||||
@@ -238,7 +238,7 @@ defineExpose({ validate });
|
||||
<ErrorModal title="流程设计校验不通过" class="w-2/5">
|
||||
<div class="mb-2 text-base">以下节点配置不完善,请修改相关配置</div>
|
||||
<div
|
||||
class="mb-3 rounded-md bg-gray-100 p-2 text-sm"
|
||||
class="mb-3 rounded-md p-2 text-sm"
|
||||
v-for="(item, index) in errorModalApi.getData()"
|
||||
:key="index"
|
||||
>
|
||||
|
||||
@@ -201,7 +201,7 @@ onMounted(() => {
|
||||
</script>
|
||||
<template>
|
||||
<div class="simple-process-model-container">
|
||||
<div class="absolute right-0 top-0 bg-white">
|
||||
<div class="bg-card absolute right-0 top-0">
|
||||
<Row type="flex" justify="end">
|
||||
<ButtonGroup key="scale-control">
|
||||
<Button v-if="!readonly" @click="exportJson">
|
||||
@@ -258,7 +258,7 @@ onMounted(() => {
|
||||
>
|
||||
<div class="mb-2">以下节点内容不完善,请修改后保存</div>
|
||||
<div
|
||||
class="line-height-normal mb-3 rounded bg-gray-100 p-2"
|
||||
class="line-height-normal mb-3 rounded p-2"
|
||||
v-for="(item, index) in errorNodes"
|
||||
:key="index"
|
||||
>
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { PropType } from 'vue';
|
||||
|
||||
import type { ActionItem, PopConfirm } from './typing';
|
||||
|
||||
import { computed, toRaw } from 'vue';
|
||||
import { computed, ref, toRaw, unref, watchEffect } from 'vue';
|
||||
|
||||
import { useAccess } from '@vben/access';
|
||||
import { IconifyIcon } from '@vben/icons';
|
||||
@@ -41,6 +41,14 @@ const props = defineProps({
|
||||
|
||||
const { hasAccessByCodes } = useAccess();
|
||||
|
||||
/** 缓存处理后的actions */
|
||||
const processedActions = ref<any[]>([]);
|
||||
const processedDropdownActions = ref<any[]>([]);
|
||||
|
||||
/** 用于比较的字符串化版本 */
|
||||
const actionsStringified = ref('');
|
||||
const dropdownActionsStringified = ref('');
|
||||
|
||||
function isIfShow(action: ActionItem): boolean {
|
||||
const ifShow = action.ifShow;
|
||||
let isIfShow = true;
|
||||
@@ -57,8 +65,8 @@ function isIfShow(action: ActionItem): boolean {
|
||||
return isIfShow;
|
||||
}
|
||||
|
||||
const getActions = computed(() => {
|
||||
const actions = toRaw(props.actions) || [];
|
||||
/** 处理actions的纯函数 */
|
||||
function processActions(actions: ActionItem[]): any[] {
|
||||
return actions
|
||||
.filter((action: ActionItem) => {
|
||||
return isIfShow(action);
|
||||
@@ -74,30 +82,101 @@ const getActions = computed(() => {
|
||||
enable: !!popConfirm,
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const getDropdownList = computed((): any[] => {
|
||||
const dropDownActions = toRaw(props.dropDownActions) || [];
|
||||
/** 处理下拉菜单actions的纯函数 */
|
||||
function processDropdownActions(
|
||||
dropDownActions: ActionItem[],
|
||||
divider: boolean,
|
||||
): any[] {
|
||||
return dropDownActions
|
||||
.filter((action: ActionItem) => {
|
||||
return isIfShow(action);
|
||||
})
|
||||
.map((action: ActionItem, index: number) => {
|
||||
const { label, popConfirm } = action;
|
||||
delete action.icon;
|
||||
const processedAction = { ...action };
|
||||
delete processedAction.icon;
|
||||
return {
|
||||
...action,
|
||||
...processedAction,
|
||||
...popConfirm,
|
||||
onConfirm: popConfirm?.confirm,
|
||||
onCancel: popConfirm?.cancel,
|
||||
text: label,
|
||||
divider: index < dropDownActions.length - 1 ? props.divider : false,
|
||||
divider: index < dropDownActions.length - 1 ? divider : false,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/** 监听actions变化并更新缓存 */
|
||||
watchEffect(() => {
|
||||
const rawActions = toRaw(props.actions) || [];
|
||||
const currentStringified = JSON.stringify(
|
||||
rawActions.map((a) => ({
|
||||
...a,
|
||||
onClick: undefined, // 排除函数以便比较
|
||||
popConfirm: a.popConfirm
|
||||
? { ...a.popConfirm, confirm: undefined, cancel: undefined }
|
||||
: undefined,
|
||||
})),
|
||||
);
|
||||
|
||||
if (currentStringified !== actionsStringified.value) {
|
||||
actionsStringified.value = currentStringified;
|
||||
processedActions.value = processActions(rawActions);
|
||||
}
|
||||
});
|
||||
|
||||
/** 监听dropDownActions变化并更新缓存 */
|
||||
watchEffect(() => {
|
||||
const rawDropDownActions = toRaw(props.dropDownActions) || [];
|
||||
const currentStringified = JSON.stringify({
|
||||
actions: rawDropDownActions.map((a) => ({
|
||||
...a,
|
||||
onClick: undefined, // 排除函数以便比较
|
||||
popConfirm: a.popConfirm
|
||||
? { ...a.popConfirm, confirm: undefined, cancel: undefined }
|
||||
: undefined,
|
||||
})),
|
||||
divider: props.divider,
|
||||
});
|
||||
|
||||
if (currentStringified !== dropdownActionsStringified.value) {
|
||||
dropdownActionsStringified.value = currentStringified;
|
||||
processedDropdownActions.value = processDropdownActions(
|
||||
rawDropDownActions,
|
||||
props.divider,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const getActions = computed(() => processedActions.value);
|
||||
|
||||
const getDropdownList = computed(() => processedDropdownActions.value);
|
||||
|
||||
/** 缓存Space组件的size计算结果 */
|
||||
const spaceSize = computed(() => {
|
||||
return unref(getActions)?.some((item: ActionItem) => item.type === 'link')
|
||||
? 0
|
||||
: 8;
|
||||
});
|
||||
|
||||
/** 缓存PopConfirm属性 */
|
||||
const popConfirmPropsMap = new Map<string, any>();
|
||||
|
||||
function getPopConfirmProps(attrs: PopConfirm) {
|
||||
const originAttrs: any = attrs;
|
||||
const key = JSON.stringify({
|
||||
title: attrs.title,
|
||||
okText: attrs.okText,
|
||||
cancelText: attrs.cancelText,
|
||||
disabled: attrs.disabled,
|
||||
});
|
||||
|
||||
if (popConfirmPropsMap.has(key)) {
|
||||
return popConfirmPropsMap.get(key);
|
||||
}
|
||||
|
||||
const originAttrs: any = { ...attrs };
|
||||
delete originAttrs.icon;
|
||||
if (attrs.confirm && isFunction(attrs.confirm)) {
|
||||
originAttrs.onConfirm = attrs.confirm;
|
||||
@@ -107,34 +186,76 @@ function getPopConfirmProps(attrs: PopConfirm) {
|
||||
originAttrs.onCancel = attrs.cancel;
|
||||
delete originAttrs.cancel;
|
||||
}
|
||||
|
||||
popConfirmPropsMap.set(key, originAttrs);
|
||||
return originAttrs;
|
||||
}
|
||||
|
||||
/** 缓存Button属性 */
|
||||
const buttonPropsMap = new Map<string, any>();
|
||||
|
||||
function getButtonProps(action: ActionItem) {
|
||||
const key = JSON.stringify({
|
||||
type: action.type,
|
||||
disabled: action.disabled,
|
||||
loading: action.loading,
|
||||
size: action.size,
|
||||
});
|
||||
|
||||
if (buttonPropsMap.has(key)) {
|
||||
return { ...buttonPropsMap.get(key) };
|
||||
}
|
||||
|
||||
const res = {
|
||||
type: action.type || 'primary',
|
||||
...action,
|
||||
disabled: action.disabled,
|
||||
loading: action.loading,
|
||||
size: action.size,
|
||||
};
|
||||
delete res.icon;
|
||||
|
||||
buttonPropsMap.set(key, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/** 缓存Tooltip属性 */
|
||||
const tooltipPropsMap = new Map<string, any>();
|
||||
|
||||
function getTooltipProps(tooltip: any | string) {
|
||||
if (!tooltip) return {};
|
||||
|
||||
const key = typeof tooltip === 'string' ? tooltip : JSON.stringify(tooltip);
|
||||
|
||||
if (tooltipPropsMap.has(key)) {
|
||||
return tooltipPropsMap.get(key);
|
||||
}
|
||||
|
||||
const result =
|
||||
typeof tooltip === 'string' ? { title: tooltip } : { ...tooltip };
|
||||
|
||||
tooltipPropsMap.set(key, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
function handleMenuClick(e: any) {
|
||||
const action = getDropdownList.value[e.key];
|
||||
if (action.onClick && isFunction(action.onClick)) {
|
||||
action.onClick();
|
||||
}
|
||||
}
|
||||
|
||||
/** 生成稳定的key */
|
||||
function getActionKey(action: ActionItem, index: number) {
|
||||
return `${action.label || ''}-${action.type || ''}-${index}`;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="table-actions">
|
||||
<Space
|
||||
:size="
|
||||
getActions?.some((item: ActionItem) => item.type === 'link') ? 0 : 8
|
||||
"
|
||||
>
|
||||
<template v-for="(action, index) in getActions" :key="index">
|
||||
<Space :size="spaceSize">
|
||||
<template
|
||||
v-for="(action, index) in getActions"
|
||||
:key="getActionKey(action, index)"
|
||||
>
|
||||
<Popconfirm
|
||||
v-if="action.popConfirm"
|
||||
v-bind="getPopConfirmProps(action.popConfirm)"
|
||||
@@ -142,13 +263,7 @@ function handleMenuClick(e: any) {
|
||||
<template v-if="action.popConfirm.icon" #icon>
|
||||
<IconifyIcon :icon="action.popConfirm.icon" />
|
||||
</template>
|
||||
<Tooltip
|
||||
v-bind="
|
||||
typeof action.tooltip === 'string'
|
||||
? { title: action.tooltip }
|
||||
: { ...action.tooltip }
|
||||
"
|
||||
>
|
||||
<Tooltip v-bind="getTooltipProps(action.tooltip)">
|
||||
<Button v-bind="getButtonProps(action)">
|
||||
<template v-if="action.icon" #icon>
|
||||
<IconifyIcon :icon="action.icon" />
|
||||
@@ -157,14 +272,7 @@ function handleMenuClick(e: any) {
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Popconfirm>
|
||||
<Tooltip
|
||||
v-else
|
||||
v-bind="
|
||||
typeof action.tooltip === 'string'
|
||||
? { title: action.tooltip }
|
||||
: { ...action.tooltip }
|
||||
"
|
||||
>
|
||||
<Tooltip v-else v-bind="getTooltipProps(action.tooltip)">
|
||||
<Button v-bind="getButtonProps(action)" @click="action.onClick">
|
||||
<template v-if="action.icon" #icon>
|
||||
<IconifyIcon :icon="action.icon" />
|
||||
@@ -185,8 +293,13 @@ function handleMenuClick(e: any) {
|
||||
</Button>
|
||||
</slot>
|
||||
<template #overlay>
|
||||
<Menu @click="handleMenuClick">
|
||||
<Menu.Item v-for="(action, index) in getDropdownList" :key="index">
|
||||
<Menu>
|
||||
<Menu.Item
|
||||
v-for="(action, index) in getDropdownList"
|
||||
:key="index"
|
||||
:disabled="action.disabled"
|
||||
@click="!action.popConfirm && handleMenuClick({ key: index })"
|
||||
>
|
||||
<template v-if="action.popConfirm">
|
||||
<Popconfirm v-bind="getPopConfirmProps(action.popConfirm)">
|
||||
<template v-if="action.popConfirm.icon" #icon>
|
||||
|
||||
Reference in New Issue
Block a user