Files
jnpf_app/components/Jnpf/DateCalculate/index.vue

221 lines
4.9 KiB
Vue
Raw Normal View History

2026-01-04 11:09:06 +08:00
<template>
<view class="jnpf-calculation jnpf-calculation-right">
<u-input input-align='right' :modelValue="jnpf.toDate(innerValue, format)" disabled placeholder='' />
</view>
</template>
<script>
import {
dayjs
} from '@/uni_modules/iRainna-dayjs/js_sdk/dayjs.min.js'
const calcRPN = rpnExps => {
rpnExps = rpnExps.concat()
const calc = (x, y, type) => {
let a1 = Number(x),
a2 = Number(y)
switch (type) {
case '+':
return a1 + a2;
case '-':
return a1 - a2;
case '×':
return a1 * a2;
case '÷':
return a1 / a2;
}
}
for (let i = 2; i < rpnExps.length; i++) {
if ('+-×÷'.includes(rpnExps[i])) {
let val = calc(rpnExps[i - 2], rpnExps[i - 1], rpnExps[i])
rpnExps.splice(i - 2, 3, val)
i = i - 2
}
}
return rpnExps[0]
}
const mergeNumberOfExps = expressions => {
const res = []
const isNumChar = n => /^[\d|\.]$/.test(n)
for (let i = 0; i < expressions.length; i++) {
if (i > 0 && isNumChar(expressions[i - 1]) && isNumChar(expressions[i])) {
res[res.length - 1] += expressions[i]
continue
}
res.push(expressions[i])
}
return res
}
export default {
name: 'jnpf-date-calculation',
props: {
modelValue: {
type: [String, Number],
default: ''
},
expression: {
type: Array,
default: []
},
formData: {
type: Object,
default: {}
},
rowIndex: {
type: [String, Number],
default: ''
},
startRelationField: String,
startTimeValue: [String, Number],
startTimeType: {
default: 1,
type: Number,
},
format: {
default: 'yyyy-MM-dd',
type: String,
},
},
data() {
return {
innerValue: '',
startTime: new Date(),
}
},
computed: {
getExp() {
return mergeNumberOfExps(this.expression)
},
},
watch: {
formData: {
handler(val, oldVal) {
setTimeout(() => {
this.execRPN()
}, 0)
},
deep: true,
immediate: true
},
modelValue: {
handler(val, oldVal) {
this.innerValue = val
},
deep: true,
immediate: true
},
},
methods: {
/**
* 计算表达式
*/
execRPN() {
const temp = this.getExp.map(t => typeof t === 'object' ? this.getFormVal(t.__vModel__) : t)
if (this.startTimeType == 1) this.startTime = this.startTimeValue;
if (this.startTimeType == 2) this.startTime = this.getFormVal(this.startRelationField);
this.innerValue = this.calcDate(this.startTime, this.getDateInfo(temp));
this.$emit('update:modelValue', this.innerValue)
},
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
};
},
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(this.jnpf.getDateTimeUnit(this.format)).valueOf();
},
/**
* 获取指定组件的值
*/
getFormVal(vModel) {
try {
if (vModel.indexOf('.') > -1) {
let [tableVModel, cmpVModel] = vModel.split('.');
if (typeof this.rowIndex === 'number') {
if (!Array.isArray(this.formData[tableVModel]) || this.formData[tableVModel].length < this
.rowIndex + 1) return 0;
return this.formData[tableVModel][this.rowIndex][cmpVModel] || 0;
} else {
if (!this.formData[tableVModel].length) return 0;
return this.formData[tableVModel].reduce((sum, c) => (c[cmpVModel] ? Number(c[cmpVModel]) :
0) + sum, 0);
}
}
return this.formData[vModel] || 0
} catch (error) {
console.warn('计算公式出错, 可能包含无效的组件值', error)
return 0
}
},
}
}
</script>
<style lang="scss" scoped>
.jnpf-calculation {
width: 100%;
&.jnpf-calculation-right {
text-align: right;
}
.tips {
color: #999999;
line-height: 40rpx;
}
.unit {
padding-left: 10rpx;
}
}
</style>