1
0

index.js 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. const {
  2. formatMagnitudeNumber,
  3. getOption,
  4. normalizeIndex,
  5. parseLooseNumber,
  6. selectBestUnit
  7. } = require('../calculator-helpers.js')
  8. const MODE_OPTIONS = [
  9. { key: 'water', label: '水侧冷量' },
  10. { key: 'airSensible', label: '风侧显热' },
  11. { key: 'airEnthalpy', label: '风侧焓差' },
  12. { key: 'cop', label: 'COP' },
  13. { key: 'carnot', label: '卡诺COP' },
  14. { key: 'temperature', label: '过热过冷' }
  15. ]
  16. const FIELD_GROUPS = {
  17. airEnthalpy: [
  18. { key: 'coolingAirFlow', label: '风量', unit: 'm³/h', placeholder: '3000' },
  19. { key: 'coolingAirInletEnthalpy', label: '入口焓值', unit: 'kJ/kg', placeholder: '58' },
  20. { key: 'coolingAirOutletEnthalpy', label: '出口焓值', unit: 'kJ/kg', placeholder: '42' }
  21. ],
  22. airSensible: [
  23. { key: 'coolingAirFlow', label: '风量', unit: 'm³/h', placeholder: '3000' },
  24. { key: 'coolingAirInletTemp', label: '入口温度', unit: '°C', placeholder: '27' },
  25. { key: 'coolingAirOutletTemp', label: '出口温度', unit: '°C', placeholder: '15' }
  26. ],
  27. carnot: [
  28. { key: 'coolingEvapTemp', label: '蒸发温度', unit: '°C', placeholder: '0' },
  29. { key: 'coolingCondTemp', label: '冷凝温度', unit: '°C', placeholder: '40' }
  30. ],
  31. cop: [
  32. { key: 'coolingCapacity', label: '制冷量', unit: 'kW', placeholder: '10' },
  33. { key: 'coolingInputPower', label: '输入功率', unit: 'kW', placeholder: '2.5' }
  34. ],
  35. temperature: [
  36. { key: 'coolingSuctionTemp', label: '吸气温度', unit: '°C', placeholder: '8' },
  37. { key: 'coolingEvapTemp', label: '蒸发饱和温度', unit: '°C', placeholder: '2' },
  38. { key: 'coolingCondTemp', label: '冷凝饱和温度', unit: '°C', placeholder: '45' },
  39. { key: 'coolingLiquidTemp', label: '液管温度', unit: '°C', placeholder: '39' }
  40. ],
  41. water: [
  42. { key: 'coolingWaterFlow', label: '水流量', unit: 'm³/h', placeholder: '10' },
  43. { key: 'coolingWaterInlet', label: '入口温度', unit: '°C', placeholder: '12' },
  44. { key: 'coolingWaterOutlet', label: '出口温度', unit: '°C', placeholder: '7' }
  45. ]
  46. }
  47. const FORMULA_TEXT = {
  48. airEnthalpy: 'Q = 风量 × Δh / 3000',
  49. airSensible: 'Q = 0.000335 × 风量 × ΔT',
  50. carnot: 'COP = Te(K) / (Tc(K) - Te(K))',
  51. cop: 'COP = 制冷量 / 输入功率',
  52. temperature: '过热度 = 吸气 - 蒸发饱和,过冷度 = 冷凝饱和 - 液管',
  53. water: 'Q = 1.163 × 水流量 × ΔT'
  54. }
  55. const POWER_UNITS = [
  56. { label: 'W', factor: 0.001 },
  57. { label: 'kW', factor: 1 },
  58. { label: 'MW', factor: 1000 }
  59. ]
  60. const COOLING_FORMAT_STEPS = [
  61. { min: 1000, decimals: 2 },
  62. { min: 1, decimals: 3 },
  63. { min: 0.001, decimals: 5 },
  64. { min: 0, decimals: 8 }
  65. ]
  66. const COOLING_VALUE_KEYS = [
  67. 'coolingAirFlow',
  68. 'coolingAirInletEnthalpy',
  69. 'coolingAirInletTemp',
  70. 'coolingAirOutletEnthalpy',
  71. 'coolingAirOutletTemp',
  72. 'coolingCapacity',
  73. 'coolingCondTemp',
  74. 'coolingEvapTemp',
  75. 'coolingInputPower',
  76. 'coolingLiquidTemp',
  77. 'coolingSuctionTemp',
  78. 'coolingWaterFlow',
  79. 'coolingWaterInlet',
  80. 'coolingWaterOutlet'
  81. ]
  82. function formatNumber(value) {
  83. return formatMagnitudeNumber(value, {
  84. fallbackText: '--',
  85. steps: COOLING_FORMAT_STEPS
  86. })
  87. }
  88. function formatPower(kwValue) {
  89. const unit = selectBestUnit(POWER_UNITS, kwValue, 1).unit
  90. return `${formatNumber(kwValue / unit.factor)} ${unit.label}`
  91. }
  92. function makeRow(label, value, unit = '') {
  93. return {
  94. label,
  95. value: unit ? `${formatNumber(value)} ${unit}` : formatNumber(value)
  96. }
  97. }
  98. function hasAll(values, keys) {
  99. return keys.every((key) => Number.isFinite(values[key]))
  100. }
  101. function calculate(modeKey, values) {
  102. if (Object.keys(values).some((key) => Number.isNaN(values[key]))) {
  103. return {
  104. errorText: '输入值格式无效',
  105. resultRows: []
  106. }
  107. }
  108. if (modeKey === 'water') {
  109. if (!hasAll(values, ['coolingWaterFlow', 'coolingWaterInlet', 'coolingWaterOutlet'])) return { errorText: '', resultRows: [] }
  110. if (values.coolingWaterFlow < 0) return { errorText: '流量不能为负数', resultRows: [] }
  111. const deltaT = Math.abs(values.coolingWaterInlet - values.coolingWaterOutlet)
  112. const capacityKw = 1.163 * values.coolingWaterFlow * deltaT
  113. return {
  114. errorText: '',
  115. resultRows: [
  116. { label: '冷量', value: formatPower(capacityKw) },
  117. makeRow('温差', deltaT, '°C'),
  118. makeRow('冷吨', capacityKw / 3.517, 'RT')
  119. ]
  120. }
  121. }
  122. if (modeKey === 'airSensible') {
  123. if (!hasAll(values, ['coolingAirFlow', 'coolingAirInletTemp', 'coolingAirOutletTemp'])) return { errorText: '', resultRows: [] }
  124. if (values.coolingAirFlow < 0) return { errorText: '风量不能为负数', resultRows: [] }
  125. const deltaT = Math.abs(values.coolingAirInletTemp - values.coolingAirOutletTemp)
  126. const capacityKw = 0.000335 * values.coolingAirFlow * deltaT
  127. return {
  128. errorText: '',
  129. resultRows: [
  130. { label: '显热冷量', value: formatPower(capacityKw) },
  131. makeRow('温差', deltaT, '°C'),
  132. makeRow('冷吨', capacityKw / 3.517, 'RT')
  133. ]
  134. }
  135. }
  136. if (modeKey === 'airEnthalpy') {
  137. if (!hasAll(values, ['coolingAirFlow', 'coolingAirInletEnthalpy', 'coolingAirOutletEnthalpy'])) return { errorText: '', resultRows: [] }
  138. if (values.coolingAirFlow < 0) return { errorText: '风量不能为负数', resultRows: [] }
  139. const deltaH = Math.abs(values.coolingAirInletEnthalpy - values.coolingAirOutletEnthalpy)
  140. const capacityKw = values.coolingAirFlow * deltaH / 3000
  141. return {
  142. errorText: '',
  143. resultRows: [
  144. { label: '总冷量', value: formatPower(capacityKw) },
  145. makeRow('焓差', deltaH, 'kJ/kg'),
  146. makeRow('冷吨', capacityKw / 3.517, 'RT')
  147. ]
  148. }
  149. }
  150. if (modeKey === 'cop') {
  151. if (!hasAll(values, ['coolingCapacity', 'coolingInputPower'])) return { errorText: '', resultRows: [] }
  152. if (values.coolingCapacity < 0 || values.coolingInputPower <= 0) return { errorText: '制冷量需大于等于0,输入功率需大于0', resultRows: [] }
  153. const cop = values.coolingCapacity / values.coolingInputPower
  154. return {
  155. errorText: '',
  156. resultRows: [
  157. makeRow('COP', cop),
  158. makeRow('EER', cop * 3.412),
  159. { label: '制冷量', value: formatPower(values.coolingCapacity) }
  160. ]
  161. }
  162. }
  163. if (modeKey === 'carnot') {
  164. if (!hasAll(values, ['coolingEvapTemp', 'coolingCondTemp'])) return { errorText: '', resultRows: [] }
  165. const evapK = values.coolingEvapTemp + 273.15
  166. const condK = values.coolingCondTemp + 273.15
  167. if (evapK <= 0 || condK <= evapK) return { errorText: '冷凝温度需高于蒸发温度,且绝对温度需大于0K', resultRows: [] }
  168. const coolingCop = evapK / (condK - evapK)
  169. const heatingCop = condK / (condK - evapK)
  170. return {
  171. errorText: '',
  172. resultRows: [
  173. makeRow('制冷COP', coolingCop),
  174. makeRow('制热COP', heatingCop),
  175. makeRow('温差', values.coolingCondTemp - values.coolingEvapTemp, '°C')
  176. ]
  177. }
  178. }
  179. if (modeKey === 'temperature') {
  180. if (!hasAll(values, ['coolingSuctionTemp', 'coolingEvapTemp', 'coolingCondTemp', 'coolingLiquidTemp'])) return { errorText: '', resultRows: [] }
  181. return {
  182. errorText: '',
  183. resultRows: [
  184. makeRow('过热度', values.coolingSuctionTemp - values.coolingEvapTemp, '°C'),
  185. makeRow('过冷度', values.coolingCondTemp - values.coolingLiquidTemp, '°C')
  186. ]
  187. }
  188. }
  189. return {
  190. errorText: '',
  191. resultRows: []
  192. }
  193. }
  194. function buildState(source = {}) {
  195. const modeIndex = normalizeIndex(source.coolingModeIndex, MODE_OPTIONS, 0)
  196. const mode = getOption(MODE_OPTIONS, modeIndex)
  197. const rawValues = COOLING_VALUE_KEYS.reduce((result, key) => {
  198. result[key] = String(source[key] === undefined || source[key] === null ? '' : source[key])
  199. return result
  200. }, {})
  201. const values = COOLING_VALUE_KEYS.reduce((result, key) => {
  202. result[key] = parseLooseNumber(rawValues[key])
  203. return result
  204. }, {})
  205. const result = calculate(mode.key, values)
  206. const fieldRows = (FIELD_GROUPS[mode.key] || []).map((field) => ({
  207. ...field,
  208. value: rawValues[field.key]
  209. }))
  210. return {
  211. ...rawValues,
  212. coolingAnyInput: COOLING_VALUE_KEYS.some((key) => rawValues[key].trim()),
  213. coolingErrorText: result.errorText,
  214. coolingFieldRows: fieldRows,
  215. coolingFormulaText: FORMULA_TEXT[mode.key] || '',
  216. coolingModeIndex: modeIndex,
  217. coolingModeKey: mode.key,
  218. coolingModeOptions: MODE_OPTIONS,
  219. coolingModeText: mode.label,
  220. coolingResultRows: result.resultRows
  221. }
  222. }
  223. function createInitialState() {
  224. return buildState({})
  225. }
  226. function updateState(state, changedData = {}) {
  227. return buildState({
  228. ...state,
  229. ...changedData
  230. })
  231. }
  232. function clearInputs(state) {
  233. const changedData = COOLING_VALUE_KEYS.reduce((result, key) => {
  234. result[key] = ''
  235. return result
  236. }, {})
  237. return updateState(state, changedData)
  238. }
  239. module.exports = {
  240. MODE_OPTIONS,
  241. clearInputs,
  242. createInitialState,
  243. updateState
  244. }