index.vue 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. <template>
  2. <view class="jnpf-calculation jnpf-calculation-right">
  3. <u-input input-align='right' :modelValue="jnpf.toDate(innerValue, format)" disabled placeholder='' />
  4. </view>
  5. </template>
  6. <script>
  7. import {
  8. dayjs
  9. } from '@/uni_modules/iRainna-dayjs/js_sdk/dayjs.min.js'
  10. const calcRPN = rpnExps => {
  11. rpnExps = rpnExps.concat()
  12. const calc = (x, y, type) => {
  13. let a1 = Number(x),
  14. a2 = Number(y)
  15. switch (type) {
  16. case '+':
  17. return a1 + a2;
  18. case '-':
  19. return a1 - a2;
  20. case '×':
  21. return a1 * a2;
  22. case '÷':
  23. return a1 / a2;
  24. }
  25. }
  26. for (let i = 2; i < rpnExps.length; i++) {
  27. if ('+-×÷'.includes(rpnExps[i])) {
  28. let val = calc(rpnExps[i - 2], rpnExps[i - 1], rpnExps[i])
  29. rpnExps.splice(i - 2, 3, val)
  30. i = i - 2
  31. }
  32. }
  33. return rpnExps[0]
  34. }
  35. const mergeNumberOfExps = expressions => {
  36. const res = []
  37. const isNumChar = n => /^[\d|\.]$/.test(n)
  38. for (let i = 0; i < expressions.length; i++) {
  39. if (i > 0 && isNumChar(expressions[i - 1]) && isNumChar(expressions[i])) {
  40. res[res.length - 1] += expressions[i]
  41. continue
  42. }
  43. res.push(expressions[i])
  44. }
  45. return res
  46. }
  47. export default {
  48. name: 'jnpf-date-calculation',
  49. props: {
  50. modelValue: {
  51. type: [String, Number],
  52. default: ''
  53. },
  54. expression: {
  55. type: Array,
  56. default: []
  57. },
  58. formData: {
  59. type: Object,
  60. default: {}
  61. },
  62. rowIndex: {
  63. type: [String, Number],
  64. default: ''
  65. },
  66. startRelationField: String,
  67. startTimeValue: [String, Number],
  68. startTimeType: {
  69. default: 1,
  70. type: Number,
  71. },
  72. format: {
  73. default: 'yyyy-MM-dd',
  74. type: String,
  75. },
  76. },
  77. data() {
  78. return {
  79. innerValue: '',
  80. startTime: new Date(),
  81. }
  82. },
  83. computed: {
  84. getExp() {
  85. return mergeNumberOfExps(this.expression)
  86. },
  87. },
  88. watch: {
  89. formData: {
  90. handler(val, oldVal) {
  91. setTimeout(() => {
  92. this.execRPN()
  93. }, 0)
  94. },
  95. deep: true,
  96. immediate: true
  97. },
  98. modelValue: {
  99. handler(val, oldVal) {
  100. this.innerValue = val
  101. },
  102. deep: true,
  103. immediate: true
  104. },
  105. },
  106. methods: {
  107. /**
  108. * 计算表达式
  109. */
  110. execRPN() {
  111. const temp = this.getExp.map(t => typeof t === 'object' ? this.getFormVal(t.__vModel__) : t)
  112. if (this.startTimeType == 1) this.startTime = this.startTimeValue;
  113. if (this.startTimeType == 2) this.startTime = this.getFormVal(this.startRelationField);
  114. this.innerValue = this.calcDate(this.startTime, this.getDateInfo(temp));
  115. this.$emit('update:modelValue', this.innerValue)
  116. },
  117. getDateInfo(exp) {
  118. let days = 0;
  119. let months = 0;
  120. let years = 0;
  121. let hours = 0;
  122. let minutes = 0;
  123. let seconds = 0;
  124. for (let i = 0; i < exp.length; i += 3) {
  125. const sign = exp[i];
  126. const value = Number.parseInt(exp[i + 1], 10);
  127. const unit = exp[i + 2];
  128. const factor = sign === '+' ? 1 : -1;
  129. switch (unit) {
  130. case 'd': {
  131. days += factor * value;
  132. break;
  133. }
  134. case 'h': {
  135. hours += factor * value;
  136. break;
  137. }
  138. case 'M': {
  139. months += factor * value;
  140. break;
  141. }
  142. case 'm': {
  143. minutes += factor * value;
  144. break;
  145. }
  146. case 's': {
  147. seconds += factor * value;
  148. break;
  149. }
  150. case 'Y': {
  151. years += factor * value;
  152. break;
  153. }
  154. }
  155. }
  156. return {
  157. days,
  158. hours,
  159. minutes,
  160. months,
  161. seconds,
  162. years
  163. };
  164. },
  165. calcDate(date, change) {
  166. if (!date) return '';
  167. const newDate = new Date(date);
  168. newDate.setFullYear(newDate.getFullYear() + change.years);
  169. newDate.setMonth(newDate.getMonth() + change.months);
  170. newDate.setDate(newDate.getDate() + change.days);
  171. newDate.setHours(newDate.getHours() + change.hours);
  172. newDate.setMinutes(newDate.getMinutes() + change.minutes);
  173. newDate.setSeconds(newDate.getSeconds() + change.seconds);
  174. return dayjs(newDate).startOf(this.jnpf.getDateTimeUnit(this.format)).valueOf();
  175. },
  176. /**
  177. * 获取指定组件的值
  178. */
  179. getFormVal(vModel) {
  180. try {
  181. if (vModel.indexOf('.') > -1) {
  182. let [tableVModel, cmpVModel] = vModel.split('.');
  183. if (typeof this.rowIndex === 'number') {
  184. if (!Array.isArray(this.formData[tableVModel]) || this.formData[tableVModel].length < this
  185. .rowIndex + 1) return 0;
  186. return this.formData[tableVModel][this.rowIndex][cmpVModel] || 0;
  187. } else {
  188. if (!this.formData[tableVModel].length) return 0;
  189. return this.formData[tableVModel].reduce((sum, c) => (c[cmpVModel] ? Number(c[cmpVModel]) :
  190. 0) + sum, 0);
  191. }
  192. }
  193. return this.formData[vModel] || 0
  194. } catch (error) {
  195. console.warn('计算公式出错, 可能包含无效的组件值', error)
  196. return 0
  197. }
  198. },
  199. }
  200. }
  201. </script>
  202. <style lang="scss" scoped>
  203. .jnpf-calculation {
  204. width: 100%;
  205. &.jnpf-calculation-right {
  206. text-align: right;
  207. }
  208. .tips {
  209. color: #999999;
  210. line-height: 40rpx;
  211. }
  212. .unit {
  213. padding-left: 10rpx;
  214. }
  215. }
  216. </style>