<script lang="ts" setup>
|
import { computed, ref, unref, watch } from 'vue';
|
|
import { useAttrs } from '@jnpf/hooks';
|
import { formatToDateTime, getDateTimeUnit, mergeNumberOfExps } from '@jnpf/utils';
|
|
import { $t } from '@vben/locales';
|
|
import { useDebounceFn } from '@vueuse/core';
|
import { Form } from 'ant-design-vue';
|
import dayjs from 'dayjs';
|
|
defineOptions({ inheritAttrs: false, name: 'JnpfDateCalculate' });
|
const props = defineProps({
|
componentVModel: String,
|
detailed: {
|
default: false,
|
type: Boolean,
|
},
|
disabled: {
|
default: false,
|
type: Boolean,
|
},
|
expression: Array,
|
format: {
|
default: 'yyyy-MM-dd',
|
type: String,
|
},
|
formData: Object,
|
isStorage: {
|
default: 0,
|
type: Number,
|
},
|
rowIndex: Number,
|
startRelationField: String,
|
startTimeType: {
|
default: 1,
|
type: Number,
|
},
|
startTimeValue: [Number, String],
|
tableVModel: String,
|
value: [Number, String],
|
});
|
const emit = defineEmits(['update:value', 'change']);
|
const attrs: any = useAttrs({ excludeDefaultKeys: false });
|
const innerValue = ref<any>('');
|
const computeExps = ref<any>(null);
|
const formItemContext = Form.useInjectFormItemContext();
|
const startTime = ref<any>(new Date());
|
|
const getExp = computed(() => mergeNumberOfExps(props.expression));
|
const getStyle = computed(() => (Reflect.has(unref(attrs), 'style') ? unref(attrs).style : {}));
|
const getBindValue = computed(() => ({
|
disabled: props.disabled,
|
placeholder: props.isStorage ? $t('component.jnpf.calculate.storage') : $t('component.jnpf.calculate.unStorage'),
|
readonly: true,
|
}));
|
|
watch(
|
() => props.formData,
|
(val) => {
|
if (!val) return;
|
if (!computeExps.value) {
|
// formData更新可能比较频繁
|
computeExps.value = useDebounceFn(execRPN, 100);
|
}
|
unref(computeExps)();
|
},
|
{ deep: true, immediate: true },
|
);
|
watch(
|
() => unref(props.value),
|
(val) => {
|
innerValue.value = val;
|
},
|
{ immediate: true },
|
);
|
|
/**
|
* 获取指定组件的值
|
*/
|
function getFormVal(vModel) {
|
try {
|
const formData: any = props.formData;
|
if (vModel.includes('.')) {
|
const [tableVModel, cmpVModel] = vModel.split('.');
|
if (typeof props.rowIndex === 'number') {
|
if (!Array.isArray(formData[tableVModel]) || formData[tableVModel].length < props.rowIndex + 1) return 0;
|
return formData[tableVModel][props.rowIndex][cmpVModel] || 0;
|
} else {
|
if (formData[tableVModel].length === 0) return 0;
|
return formData[tableVModel].reduce((sum, c) => (c[cmpVModel] ? Number(c[cmpVModel]) : 0) + sum, 0);
|
}
|
}
|
return formData[vModel] || 0;
|
} catch (error) {
|
console.warn('日期公式出错, 可能包含无效的组件值', error);
|
return 0;
|
}
|
}
|
/**
|
* 计算表达式
|
*/
|
function execRPN() {
|
const formData: any = props.formData;
|
const temp = unref(getExp).map((t) => (typeof t === 'object' ? getFormVal(t.__vModel__) : t));
|
if (props.startTimeType == 1) startTime.value = props.startTimeValue;
|
if (props.startTimeType == 2) startTime.value = getFormVal(props.startRelationField);
|
innerValue.value = calcDate(startTime.value, getDateInfo(temp));
|
if ((props.rowIndex as any) >= 0 && props.componentVModel && props.tableVModel) {
|
if (
|
formData[props.tableVModel][props.rowIndex as any] &&
|
formData[props.tableVModel][props.rowIndex as any][props.componentVModel] !== innerValue.value &&
|
props.isStorage
|
) {
|
emit('update:value', innerValue.value);
|
emit('change', innerValue.value);
|
formItemContext.onFieldChange();
|
}
|
} else {
|
if (props.isStorage) {
|
emit('update:value', innerValue.value);
|
formItemContext.onFieldChange();
|
}
|
}
|
}
|
function getDateInfo(exp) {
|
let days = 0;
|
let months = 0;
|
let years = 0;
|
let hours = 0;
|
let minutes = 0;
|
let seconds = 0;
|
for (let i = 0; i < exp.length; i += 3) {
|
const sign = exp[i];
|
const value = Number.parseInt(exp[i + 1], 10);
|
const unit = exp[i + 2];
|
const factor = sign === '+' ? 1 : -1;
|
switch (unit) {
|
case 'd': {
|
days += factor * value;
|
break;
|
}
|
case 'h': {
|
hours += factor * value;
|
break;
|
}
|
case 'M': {
|
months += factor * value;
|
break;
|
}
|
case 'm': {
|
minutes += factor * value;
|
break;
|
}
|
case 's': {
|
seconds += factor * value;
|
break;
|
}
|
case 'Y': {
|
years += factor * value;
|
break;
|
}
|
}
|
}
|
return { days, hours, minutes, months, seconds, years };
|
}
|
function calcDate(date, change) {
|
if (!date) return '';
|
const newDate = new Date(date);
|
newDate.setFullYear(newDate.getFullYear() + change.years);
|
newDate.setMonth(newDate.getMonth() + change.months);
|
newDate.setDate(newDate.getDate() + change.days);
|
newDate.setHours(newDate.getHours() + change.hours);
|
newDate.setMinutes(newDate.getMinutes() + change.minutes);
|
newDate.setSeconds(newDate.getSeconds() + change.seconds);
|
return dayjs(newDate).startOf(getDateTimeUnit(props.format)).valueOf();
|
}
|
</script>
|
|
<template>
|
<div :style="getStyle" class="jnpf-date-calculate">
|
<a-input :value="formatToDateTime(innerValue, format)" v-bind="getBindValue" v-if="!detailed" />
|
<p v-else :title="formatToDateTime(innerValue, format)" class="detail-txt leading-[32px]">{{ formatToDateTime(innerValue, format) }}</p>
|
</div>
|
</template>
|
<style lang="scss" scoped>
|
.ant-table,
|
.jnpf-vxe-table {
|
.jnpf-date-calculate {
|
.detail-txt {
|
overflow: hidden;
|
text-overflow: ellipsis;
|
line-height: 22px !important;
|
white-space: nowrap;
|
}
|
}
|
}
|
</style>
|