<script lang="ts" setup>
|
import { computed, onMounted, ref, unref } from 'vue';
|
|
import { useMessage } from '@jnpf/hooks';
|
import { BasicModal, useModal } from '@jnpf/ui/modal';
|
import { mergeNumberOfExps, validDateExp } from '@jnpf/utils';
|
|
import { ArrowLeftOutlined, DeleteOutlined } from '@ant-design/icons-vue';
|
import { cloneDeep } from 'lodash-es';
|
|
defineOptions({ inheritAttrs: false });
|
const props = defineProps(['activeData', 'drawingList']);
|
const { createMessage } = useMessage();
|
const [registerModal, { openModal, closeModal }] = useModal();
|
const expressionTemp = ref<any[]>([]);
|
const expValid = ref(true);
|
const typeOptions = [
|
{ fullName: '特定时间', id: 1 },
|
{ fullName: '表单字段', id: 2 },
|
{ fullName: '填写当前时间', id: 3 },
|
];
|
const formatOptions = [
|
{ id: 'yyyy', fullName: 'yyyy' },
|
{ id: 'yyyy-MM', fullName: 'yyyy-MM' },
|
{ id: 'yyyy-MM-dd', fullName: 'yyyy-MM-dd' },
|
{ id: 'yyyy-MM-dd HH:mm', fullName: 'yyyy-MM-dd HH:mm' },
|
{ id: 'yyyy-MM-dd HH:mm:ss', fullName: 'yyyy-MM-dd HH:mm:ss' },
|
];
|
const dateUnitList = [
|
{ fullName: 'Y', tip: '年' },
|
{ fullName: 'M', tip: '月' },
|
{ fullName: 'd', tip: '天' },
|
{ fullName: 'h', tip: '时' },
|
{ fullName: 'm', tip: '分' },
|
{ fullName: 's', tip: '秒' },
|
];
|
|
const calculateComps = computed<any[]>(() => {
|
const list: any[] = [];
|
const loop = (data, parent?) => {
|
if (!data) return;
|
if (data.__config__ && data.__config__.children && Array.isArray(data.__config__.children)) {
|
loop(data.__config__.children, data);
|
}
|
if (Array.isArray(data)) data.forEach((d) => loop(d, parent));
|
if (data.__config__ && data.__config__.jnpfKey && data.__vModel__ && ['calculate', 'inputNumber'].includes(data.__config__.jnpfKey)) {
|
const isTableChild = parent && parent.__config__ && parent.__config__.jnpfKey === 'table';
|
if (isTableChild && !isSameSource(data)) return;
|
list.push({
|
__vModel__: isTableChild ? `${parent.__vModel__}.${data.__vModel__}` : data.__vModel__,
|
label: isTableChild ? `${parent.__config__.label}.${data.__config__.label}` : data.__config__.label,
|
});
|
}
|
};
|
loop(props.drawingList);
|
return list;
|
});
|
const formFieldsOptions = computed(() => {
|
const list: any[] = [];
|
const loop = (data, parent?) => {
|
if (!data) return;
|
if (data.__config__ && isIncludesTable(data) && data.__config__.children && Array.isArray(data.__config__.children)) {
|
loop(data.__config__.children, data);
|
}
|
if (Array.isArray(data)) data.forEach((d) => loop(d, parent));
|
if (data.__vModel__ && data.__config__.jnpfKey === 'datePicker' && data.__vModel__ !== props.activeData.__vModel__) {
|
const isTableChild = parent && parent.__config__ && parent.__config__.jnpfKey === 'table';
|
list.push({
|
id: isTableChild ? `${parent.__vModel__}.${data.__vModel__}` : data.__vModel__,
|
fullName: isTableChild ? `${parent.__config__.label}-${data.__config__.label}` : data.__config__.label,
|
...data,
|
});
|
}
|
};
|
loop(props.drawingList);
|
return list;
|
});
|
|
function openCalcModal() {
|
expressionTemp.value = cloneDeep(props.activeData.expression);
|
expValid.value = true;
|
openModal();
|
}
|
function handleSubmit() {
|
if (!expressionTemp.value.length) {
|
props.activeData.expression = expressionTemp.value;
|
closeModal();
|
return;
|
}
|
const formatExp = mergeNumberOfExps(expressionTemp.value);
|
const temp = formatExp.map((t) => (typeof t === 'object' ? 1 : t));
|
const boo = expressionTemp.value.some((o) => o.label === '无效的值');
|
if (boo) return createMessage.error(`编辑的公式含有无效的值,无法计算`);
|
expValid.value = validDateExp(temp, false);
|
if (expValid.value) {
|
props.activeData.expression = expressionTemp.value;
|
closeModal();
|
} else {
|
createMessage.error(`编辑的公式不符合计算法则,无法计算`);
|
}
|
}
|
function reloadExpressionTemp() {
|
const isValid = (d) => {
|
const target = unref(calculateComps).find((cmp) => cmp.__vModel__ === d.__vModel__ && cmp.__vModel__ === d.__vModel__);
|
return !!target;
|
};
|
expressionTemp.value = props.activeData.expression.map((t) => {
|
return typeof t === 'string' || isValid(t) ? t : { __vModel__: t.__vModel__, label: '无效的值' };
|
});
|
props.activeData.expression = expressionTemp.value;
|
}
|
function isSameSource(data) {
|
const isSubTable = props.activeData.__config__.isSubTable;
|
if (isSubTable) return data.__config__.isSubTable && props.activeData.__config__.parentVModel === data.__config__.parentVModel;
|
return true;
|
}
|
function isIncludesTable(data) {
|
if ((!data.__config__.layout || data.__config__.layout === 'rowFormItem') && data.__config__.jnpfKey !== 'table') return true;
|
if (props.activeData.__config__.isSubTable) return props.activeData.__config__.parentVModel === data.__vModel__;
|
return data.__config__.jnpfKey !== 'table';
|
}
|
function onStartTimeTypeChange() {
|
props.activeData.startTimeValue = null;
|
props.activeData.startRelationField = '';
|
}
|
|
onMounted(() => {
|
reloadExpressionTemp();
|
});
|
</script>
|
<template>
|
<a-form-item label="开始">
|
<jnpf-select v-model:value="activeData.startTimeType" :options="typeOptions" @change="onStartTimeTypeChange" />
|
<div class="mt-[10px]" v-if="activeData.startTimeType != 3">
|
<jnpf-date-picker v-if="activeData.startTimeType == 1" v-model:value="activeData.startTimeValue" placeholder="请选择" format="YYYY-MM-DD HH:mm:ss" />
|
<jnpf-select v-else-if="activeData.startTimeType == 2" v-model:value="activeData.startRelationField" :options="formFieldsOptions" />
|
</div>
|
</a-form-item>
|
<a-form-item label="日期公式">
|
<div class="pane-calc-preview" @click="openCalcModal()">
|
<template v-if="activeData.expression.length">
|
<span
|
v-for="(item, index) in activeData.expression"
|
:key="index"
|
:class="{ 'calc-btn': typeof item !== 'string', error: typeof item !== 'string' && item.label === '无效的值' }">
|
{{ typeof item !== 'string' ? item.label : item }}
|
</span>
|
</template>
|
<span v-else class="placeholder-text">编辑日期公式</span>
|
</div>
|
</a-form-item>
|
<a-form-item label="格式">
|
<jnpf-select v-model:value="activeData.format" :options="formatOptions" />
|
</a-form-item>
|
<BasicModal @register="registerModal" title="编辑日期公式" @ok="handleSubmit" class="calc-modal">
|
<div class="calc-box">
|
<div class="calc-preview" :class="{ error: !expValid }">
|
日期公式 =
|
<span
|
v-for="(item, index) in expressionTemp"
|
:key="index"
|
:class="{ 'calc-btn': typeof item !== 'string', error: typeof item !== 'string' && item.label === '无效的值' }">
|
{{ typeof item !== 'string' ? item.label : item }}
|
</span>
|
<div class="preview-actions">
|
<a-tooltip title="删除" placement="bottom">
|
<ArrowLeftOutlined @click="expressionTemp.pop()" />
|
</a-tooltip>
|
<a-tooltip title="清空" placement="bottom">
|
<DeleteOutlined @click="expressionTemp = []" />
|
</a-tooltip>
|
</div>
|
</div>
|
<div class="calc-tip">输入你想要 增加/减去 的时间。如:+8h+1m,-1d+8h。请不要忘记输入单位。组件将自动计算出日期,免手动计算</div>
|
<div>
|
<span>计算对象:</span>
|
<template v-if="calculateComps.length">
|
<span v-for="item in calculateComps" :key="item.__vModel__" @click="expressionTemp.push(item)" class="calc-btn">
|
{{ item.label }}
|
</span>
|
</template>
|
<span class="empty-text" v-else>暂无数据</span>
|
</div>
|
<div class="comBtn my-[10px]">
|
<span>计算单位:</span>
|
<span v-for="item in dateUnitList" class="calc-btn" :key="item.fullName" :title="item.tip" @click="expressionTemp.push(item.fullName)">
|
{{ item.fullName }}
|
</span>
|
</div>
|
<div class="comBtn my-[10px]">
|
<span>计算符号:</span>
|
<span v-for="item in ['+', '-']" class="calc-btn" :key="item" @click="expressionTemp.push(item)">{{ item }}</span>
|
</div>
|
<div class="my-[10px]">
|
<span style="float: left">数字键盘:</span>
|
<div class="numBtn comBtn">
|
<span :key="item" class="calc-btn" v-for="item in ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '.']" @click="expressionTemp.push(item)">
|
{{ item }}
|
</span>
|
</div>
|
</div>
|
</div>
|
</BasicModal>
|
</template>
|
<style lang="scss" scoped>
|
.pane-calc-preview {
|
min-height: 32px;
|
padding: 0 11px;
|
font-size: 13px;
|
cursor: pointer;
|
border: 1px solid var(--border-color-base);
|
border-radius: 2px;
|
|
.placeholder-text {
|
font-size: 14px;
|
font-weight: 400;
|
line-height: 32px;
|
color: #bfbfbf;
|
}
|
|
span {
|
line-height: 32px;
|
}
|
|
.calc-btn {
|
&:first-child {
|
margin-left: 0;
|
}
|
}
|
}
|
|
.calc-btn {
|
padding: 4px 8px;
|
margin: 0 6px;
|
cursor: pointer;
|
background: var(--app-main-background);
|
|
&.error {
|
background: var(--error-color);
|
}
|
|
&:hover {
|
background: var(--app-content-background);
|
}
|
}
|
|
.calc-modal {
|
.calc-box {
|
font-size: 12px;
|
line-height: 2;
|
|
.calc-tip {
|
margin: 10px 0;
|
font-size: 12px;
|
color: var(--text-color-secondary);
|
}
|
|
.empty-text {
|
margin: 6px 0;
|
color: var(--text-color-secondary);
|
}
|
|
.numBtn {
|
width: 110px;
|
overflow: hidden;
|
line-height: 2.5;
|
}
|
|
.comBtn {
|
.calc-btn {
|
display: inline-block;
|
width: 22px;
|
height: 22px;
|
padding: 0;
|
line-height: 22px;
|
text-align: center;
|
}
|
}
|
|
.calc-preview {
|
position: relative;
|
min-height: 60px;
|
padding: 4px 10px;
|
border: 1px solid var(--border-color-base1);
|
border-radius: 2px;
|
|
&.error {
|
border: 1px solid var(--error-color);
|
}
|
|
.preview-actions {
|
position: absolute;
|
right: 0;
|
bottom: 0;
|
|
.anticon {
|
margin-right: 8px;
|
font-size: 14px;
|
cursor: pointer;
|
|
&:hover {
|
color: var(--error-color);
|
}
|
}
|
}
|
}
|
}
|
}
|
</style>
|