8
0

edit-formula.vue 59 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463
  1. <template>
  2. <hc-drawer v-model="isShow" ui="hc-project-list-edit-formula-drawer" to-id="hc-layout-box" is-close @close="drawerClose">
  3. <hc-card is-action-btn :scrollbar="isScrollBar">
  4. <div class="hc-project-list-edit-formula-card" :class="isScrollBar ? '' : 'is-no-scroll'">
  5. <!-- 顶部操作 -->
  6. <div class="hc-formula-card-box border-dashed-card hc-flex mb-14px h-58px">
  7. <div class="retain hc-flex h-full w-174px">
  8. <el-checkbox v-model="isRetain" size="large" />
  9. <span class="ml-5px text-14px">保留</span>
  10. <div class="relative ml-5px w-90px">
  11. <el-input-number v-model="retainNum" block :step="1" :min="0" :max="5" :disabled="!isRetain" controls-position="right" />
  12. </div>
  13. <span class="ml-5px text-14px">位</span>
  14. </div>
  15. <div class="range hc-flex h-full w-155px">
  16. <el-button :type="deviationRangeShow ? 'primary' : ''" @click="setDeviationRange">允许偏差值范围</el-button>
  17. </div>
  18. <div class="menu h-full flex-1">
  19. <hc-body padding="0">
  20. <el-menu :default-active="formulaMenuIndex" mode="horizontal" @select="handleFormulaMenu">
  21. <el-sub-menu v-for="(arr, key, index) in formulaMenuList" :key="key" :index="key">
  22. <template #title>{{ key }}</template>
  23. <el-menu-item v-for="(item, i) in arr" :key="i" :index="`${index + 1}-${i + 1}`">{{ item?.name }}</el-menu-item>
  24. </el-sub-menu>
  25. </el-menu>
  26. </hc-body>
  27. </div>
  28. <div class="hand hc-flex h-full w-100px">
  29. <el-button @click="handWritClick">手写模式</el-button>
  30. </div>
  31. </div>
  32. <!-- 函数公式 -->
  33. <div class="border-dashed-card hc-formula-card-math mb-14px">
  34. <div class="header hc-flex">
  35. <div class="name flex-1 text-14px">函数公式.</div>
  36. <div class="extra relative ml-24px">
  37. <el-button size="small" @click="clearResetFunClick">清除选择</el-button>
  38. <el-button :type="isResetFun ? 'primary' : 'info'" size="small" @click="resetFunClick">重置函数</el-button>
  39. </div>
  40. </div>
  41. <div class="body relative">
  42. <template v-for="(item, index) in resultFormula" :key="index">
  43. <span class="element-class text-22px" :class="item.selected ? 'is-cur' : ''" @click="resultFormulaItem(item, index)">{{ item.name }}</span>
  44. </template>
  45. <span class="ml-10px mr-10px text-24px">=</span>
  46. <template v-for="(item, index) in processFormula" :key="index">
  47. <el-tooltip :content="item.tableName" placement="top-start" :disabled="item.type !== 'Element' || isNullES(item.tableName)">
  48. <span class="element-class text-22px" :class="item.selected ? 'is-cur' : ''" :data-name="getItemTableName(item)" @click="processFormulaItem(item, index)">{{ item.name }}</span>
  49. </el-tooltip>
  50. </template>
  51. </div>
  52. </div>
  53. <!-- 重置函数 -->
  54. <div v-if="isResetFun" class="hc-formula-reset-fun mb-14px">
  55. <hc-body split padding="0">
  56. <template #left>
  57. <hc-card class="reset-fun-left-card" scrollbar :loading="treeResetFunLoading">
  58. <template #header>
  59. <hc-search-input v-model="resetFunTree" @search="resetFunTreeSearch" />
  60. </template>
  61. <el-tree
  62. v-if="isResetFunTreeLazy" ref="treeResetFunLazyRef" :default-expanded-keys="treeResetFunLazyExpanded" node-key="id"
  63. :props="defaultProps" :expand-on-click-node="false" lazy highlight-current :load="treeResetFunLazyLoad"
  64. @node-click="treeResetFunLazyClick"
  65. />
  66. <el-tree
  67. v-else ref="treeResetFunAllRef" :data="resetFunTreeAll" :props="defaultProps" node-key="id"
  68. :expand-on-click-node="false" @node-click="treeResetFunLazyClick"
  69. />
  70. </hc-card>
  71. </template>
  72. <hc-card class="reset-fun-right-card">
  73. <template #header>
  74. <hc-search-input v-model="resetFunEle" placeholder="请输入你想搜索的元素字段" @search="resetFunEleSearch" />
  75. </template>
  76. <div class="body h-full">
  77. <div v-loading="isResetFunEleLoading" class="tag-box">
  78. <template v-for="(item, index) in resetFunEleData" :key="index">
  79. <el-button v-if="item.k" type="primary" plain size="small" @click="resetFunEleTagClick(item)">{{ item.name }}</el-button>
  80. <el-button v-else type="primary" plain size="small" @click="resetFunEleTagClick(item)">{{ item.eName }}</el-button>
  81. </template>
  82. </div>
  83. <div class="action-box hc-flex">
  84. <div class="left hc-flex flex-1">
  85. <div class="btn hc-flex-center" @click="resetFunText">
  86. <span class="text">输入值</span>
  87. </div>
  88. <div class="btn hc-flex-center" @click="resetFunBrackets('(')">
  89. <span class="symbol">(</span>
  90. </div>
  91. <div class="btn hc-flex-center" @click="resetFunBrackets(')')">
  92. <span class="symbol">)</span>
  93. </div>
  94. <div class="btn hc-flex-center" @click="resetFunOperator('+')">
  95. <i class="i-ri-add-line" />
  96. </div>
  97. <div class="btn hc-flex-center" @click="resetFunOperator('-')">
  98. <i class="i-ri-subtract-line" />
  99. </div>
  100. <div class="btn hc-flex-center" @click="resetFunOperator('*')">
  101. <i class="i-ri-close-line" />
  102. </div>
  103. <div class="btn hc-flex-center" @click="resetFunOperator('%')">
  104. <hc-icon name="divide" />
  105. </div>
  106. </div>
  107. <div class="right hc-flex">
  108. <el-tooltip content="删除元素" placement="top-end">
  109. <div class="btn hc-flex-center" @click="resetFunDel">
  110. <i class="i-ri-delete-back-2-line" />
  111. </div>
  112. </el-tooltip>
  113. <el-tooltip content="清空所有" placement="top-end">
  114. <div class="btn hc-flex-center" @click="resetFunClear">
  115. <i class="i-ri-delete-bin-3-line" />
  116. </div>
  117. </el-tooltip>
  118. </div>
  119. </div>
  120. <div class="input-box">
  121. <draggable v-model="selectEleFormula" item-key="index">
  122. <template #item="{ element }">
  123. <span class="element-class" :class="[`is-${element.type}`, element.selected ? 'is-cur' : '']" @click="selectEleFormulaItem(element)">{{ element.name }}</span>
  124. </template>
  125. </draggable>
  126. </div>
  127. </div>
  128. </hc-card>
  129. </hc-body>
  130. </div>
  131. <!-- 函数公式运算执行溯源 -->
  132. <div v-if="!isResetFun && !deviationRangeShow && !isSelectEle" class="border-dashed-card hc-formula-card-project mb-14px">
  133. <div class="header mb-14px text-14px">函数公式运算执行溯源</div>
  134. <div class="body relative">
  135. <el-select v-model="projectId" filterable clearable class="mr-14px w-380px" placeholder="选择项目" @change="projectChange">
  136. <el-option v-for="item in projectList" :key="item.id" :label="item.projectName" :value="item.id" />
  137. </el-select>
  138. <el-select v-model="contractId" filterable clearable class="mr-14px w-200px" placeholder="请选择合同段">
  139. <el-option v-for="item in contractList" :key="item.id" :label="item.contractName" :value="item.id" />
  140. </el-select>
  141. <el-button type="info" @click="projectQueryClick">查询</el-button>
  142. </div>
  143. </div>
  144. <!-- 允许偏差值范围 -->
  145. <div v-if="deviationRangeShow && !isResetFun" class="border-dashed-card hc-formula-card-range mb-14px" :class="isRangeSelectEle ? 'is-h' : ''">
  146. <div class="hc-formula-card-range-form hc-flex mb-12px text-14px">
  147. <div>允许偏差值范围:</div>
  148. <div class="w-130px">
  149. <el-select v-model="deviationRangeSymbol" filterable clearable placeholder="请选择允许偏差值范围">
  150. <el-option label="【min,max】" value="【min,max】" />
  151. <el-option label=">" value=">" />
  152. <el-option label="<" value="<" />
  153. <el-option label="≥" value="≥" />
  154. <el-option label="≤" value="≤" />
  155. </el-select>
  156. </div>
  157. <div class="ml-50px">模式:</div>
  158. <div class="mr-50px w-100px">
  159. <el-select v-model="deviationRangeResult" filterable clearable placeholder="请选择模式" @change="deviationRangeResultChange">
  160. <el-option label="普通" value="1" />
  161. <el-option label="自定义" value="2" />
  162. </el-select>
  163. </div>
  164. <div v-if="deviationRangeResult === '1'" class="hc-flex mr-50px">
  165. <VueTagsInput
  166. v-if="!(deviationRangeSymbol === '<' || deviationRangeSymbol === '≤')" v-model="deviationRangeTag1" :tags="deviationRangeTags1"
  167. placeholder="输入/参数" class="mr-12px" :class="curRangeFocusIndex === 1 ? 'cur' : ''" @focus="curRangeFocusIndex = 1"
  168. @blur="deviationRangeBlur1" @before-adding-tag="rangeAddingTag"
  169. />
  170. <VueTagsInput
  171. v-if="!(deviationRangeSymbol === '>' || deviationRangeSymbol === '≥')" v-model="deviationRangeTag2" :tags="deviationRangeTags2"
  172. placeholder="输入/参数" :class="curRangeFocusIndex === 2 ? 'cur' : ''" @focus="curRangeFocusIndex = 2" @blur="deviationRangeBlur2"
  173. @before-adding-tag="rangeAddingTag"
  174. />
  175. </div>
  176. <el-button :type="isRangeSelectEle ? 'primary' : 'info'" @click="deviationRangeSelectEle">选择参数</el-button>
  177. </div>
  178. <div v-if="deviationRangeResult === '2'" class="hc-formula-card-range-param relative mb-12px">
  179. <el-row :gutter="20">
  180. <el-col v-if="!(deviationRangeSymbol === '<' || deviationRangeSymbol === '≤')" :span="12">
  181. <div class="deviation-range-param-card" :class="curRangeFocusIndex === 3 ? 'cur' : ''" @click.capture="curRangeFocusIndex = 3">
  182. <div class="title-box">参数1</div>
  183. <div class="action-box hc-flex">
  184. <div class="left hc-flex flex-1">
  185. <div class="btn hc-flex-center" @click="resetFunText">
  186. <span class="text">输入值</span>
  187. </div>
  188. <div class="btn hc-flex-center" @click="resetFunBrackets('(')">
  189. <span class="symbol">(</span>
  190. </div>
  191. <div class="btn hc-flex-center" @click="resetFunBrackets(')')">
  192. <span class="symbol">)</span>
  193. </div>
  194. <div class="btn hc-flex-center" @click="resetFunOperator('+')">
  195. <i class="i-ri-add-line" />
  196. </div>
  197. <div class="btn hc-flex-center" @click="resetFunOperator('-')">
  198. <i class="i-ri-subtract-line" />
  199. </div>
  200. <div class="btn hc-flex-center" @click="resetFunOperator('*')">
  201. <i class="i-ri-close-line" />
  202. </div>
  203. <div class="btn hc-flex-center" @click="resetFunOperator('%')">
  204. <hc-icon name="divide" />
  205. </div>
  206. </div>
  207. <div class="right hc-flex">
  208. <el-tooltip content="删除元素" placement="top-end">
  209. <div class="btn hc-flex-center" @click="resetFunDel">
  210. <i class="i-ri-delete-back-2-line" />
  211. </div>
  212. </el-tooltip>
  213. <el-tooltip content="清空所有" placement="top-end">
  214. <div class="btn hc-flex-center" @click="resetFunClear">
  215. <i class="i-ri-delete-bin-3-line" />
  216. </div>
  217. </el-tooltip>
  218. </div>
  219. </div>
  220. <div class="input-box">
  221. <draggable v-if="selectEleFormula3.length > 0" v-model="selectEleFormula3" item-key="index">
  222. <template #item="{ element }">
  223. <span class="element-class" :class="[`is-${element.type}`, element.selected ? 'is-cur' : '']" @click="selectEleFormulaItem(element)">{{ element.name }}</span>
  224. </template>
  225. </draggable>
  226. <div v-else class="text-gray-5">请选择元素</div>
  227. </div>
  228. </div>
  229. </el-col>
  230. <el-col v-if="!(deviationRangeSymbol === '>' || deviationRangeSymbol === '≥')" :span="12">
  231. <div class="deviation-range-param-card" :class="curRangeFocusIndex === 4 ? 'cur' : ''" @click.capture="curRangeFocusIndex = 4">
  232. <div class="title-box">参数2</div>
  233. <div class="action-box hc-flex">
  234. <div class="left hc-flex flex-1">
  235. <div class="btn hc-flex-center" @click="resetFunText">
  236. <span class="text">输入值</span>
  237. </div>
  238. <div class="btn hc-flex-center" @click="resetFunBrackets('(')">
  239. <span class="symbol">(</span>
  240. </div>
  241. <div class="btn hc-flex-center" @click="resetFunBrackets(')')">
  242. <span class="symbol">)</span>
  243. </div>
  244. <div class="btn hc-flex-center" @click="resetFunOperator('+')">
  245. <i class="i-ri-add-line" />
  246. </div>
  247. <div class="btn hc-flex-center" @click="resetFunOperator('-')">
  248. <i class="i-ri-subtract-line" />
  249. </div>
  250. <div class="btn hc-flex-center" @click="resetFunOperator('*')">
  251. <i class="i-ri-close-line" />
  252. </div>
  253. <div class="btn hc-flex-center" @click="resetFunOperator('%')">
  254. <hc-icon name="divide" />
  255. </div>
  256. </div>
  257. <div class="right hc-flex">
  258. <el-tooltip content="删除元素" placement="top-end">
  259. <div class="btn hc-flex-center" @click="resetFunDel">
  260. <i class="i-ri-delete-back-2-line" />
  261. </div>
  262. </el-tooltip>
  263. <el-tooltip content="清空所有" placement="top-end">
  264. <div class="btn hc-flex-center" @click="resetFunClear">
  265. <i class="i-ri-delete-bin-3-line" />
  266. </div>
  267. </el-tooltip>
  268. </div>
  269. </div>
  270. <div class="input-box">
  271. <draggable v-if="selectEleFormula4.length > 0" v-model="selectEleFormula4" item-key="index">
  272. <template #item="{ element }">
  273. <span class="element-class" :class="[`is-${element.type}`, element.selected ? 'is-cur' : '']" @click="selectEleFormulaItem(element)">{{ element.name }}</span>
  274. </template>
  275. </draggable>
  276. <div v-else class="text-gray-5">请选择元素</div>
  277. </div>
  278. </div>
  279. </el-col>
  280. </el-row>
  281. </div>
  282. <div v-if="isRangeSelectEle" class="hc-formula-card-range-select relative">
  283. <hc-body split padding="0">
  284. <template #left>
  285. <hc-card class="hc-formula-card-range-select-left-card" scrollbar :loading="treeResetFunLoading">
  286. <template #header>
  287. <hc-search-input v-model="resetFunTree" @search="resetFunTreeSearch" />
  288. </template>
  289. <el-tree
  290. v-if="isResetFunTreeLazy" ref="treeRangeSelectLazyRef" :default-expanded-keys="treeResetFunLazyExpanded" node-key="id"
  291. :props="defaultProps" :expand-on-click-node="false" lazy highlight-current :load="treeResetFunLazyLoad"
  292. @node-click="treeResetFunLazyClick"
  293. />
  294. <el-tree
  295. v-else ref="treeRangeSelectAllRef" :data="resetFunTreeAll" :props="defaultProps" node-key="id"
  296. :expand-on-click-node="false" @node-click="treeResetFunLazyClick"
  297. />
  298. </hc-card>
  299. </template>
  300. <hc-card scrollbar class="hc-formula-card-range-select-right-card">
  301. <template #header>
  302. <hc-search-input v-model="resetFunEle" placeholder="请输入你想搜索的元素字段" @search="resetFunEleSearch" />
  303. </template>
  304. <div v-loading="isResetFunEleLoading" class="body h-full">
  305. <template v-for="(item, index) in resetFunEleData" :key="index">
  306. <el-button v-if="item.k" type="primary" plain size="small" @click="resetFunEleTagClick(item)">{{ item.name }}</el-button>
  307. <el-button v-else type="primary" plain size="small" @click="resetFunEleTagClick(item)">{{ item.eName }}</el-button>
  308. </template>
  309. </div>
  310. </hc-card>
  311. </hc-body>
  312. </div>
  313. </div>
  314. <!-- 多标签处理 -->
  315. <div v-if="isSelectEle" class="hc-formula-card-tag mb-14px">
  316. <hc-body padding="0">
  317. <el-tabs v-model="equationSelectIndex" type="border-card" closable :before-leave="leaveEquationSelect" @tab-remove="delEquationSelect">
  318. <template v-for="(item, index) in equationSelectEle.children" :key="index">
  319. <el-tab-pane :label="item.name" :name="index">
  320. <template v-if="!['日期偏移', '日期格式化', '下标取数', '判断'].includes(item.name)">
  321. <div class="ft mb-6px">{{ getTemplateFt(item) }}</div>
  322. <div class="example mb-14px">{{ item?.example }}</div>
  323. <div class="arguments relative">
  324. <template v-for="(items, indexs) in item.arguments" :key="indexs">
  325. <div class="item hc-flex mb-10px">
  326. <span>参数{{ indexs + 1 }}({{ item.template.args[indexs].m }}):</span>
  327. <template v-if="JSON.stringify(items) !== 'null'">
  328. <el-tag v-if="(typeof items) == 'object' && (['Element', 'ParamData'].includes(items.type))">{{ items.name }}</el-tag>
  329. <el-input v-else v-model="item.arguments[indexs]" placeholder="请输入内容" class="w-200px" size="small" />
  330. </template>
  331. <el-link type="primary" class="ml-12px" @click="enterTextClick(item, indexs)">输入文本</el-link>
  332. <el-link type="primary" class="ml-12px" @click="selectingElements(item, indexs)">选择元素</el-link>
  333. <el-link type="primary" class="ml-12px" @click="setCurElement(item, index, indexs)">当前元素</el-link>
  334. </div>
  335. </template>
  336. </div>
  337. </template>
  338. <template v-else>
  339. {{ item.name }} + {{ index }}
  340. </template>
  341. </el-tab-pane>
  342. </template>
  343. </el-tabs>
  344. </hc-body>
  345. </div>
  346. </div>
  347. <template #action>
  348. <el-button @click="drawerClose">取消</el-button>
  349. <el-button type="primary" :loading="submitLoading" @click="submitClick">保存</el-button>
  350. </template>
  351. </hc-card>
  352. <!-- 手写模式 -->
  353. <hc-dialog v-model="isHandWritEle" is-table widths="900px" title="手写模式" @close="handWritEleClose">
  354. <template #search>
  355. <div class="relative">
  356. <div class="mb-6px text-orange-6">tips:手写模式不保证能转换成配置模式!!即使能转换也不保证正确!!!</div>
  357. <div class="text-orange-6">无法在手写模式手写加入新的元素!新的节点参数!</div>
  358. </div>
  359. </template>
  360. <el-input v-model="handWritText" type="textarea" class="hc-formula-hand-writ-text" placeholder="请输入内容" />
  361. <template #footer>
  362. <el-button hc-btn @click="handWritEleClose">取消</el-button>
  363. <el-button hc-btn type="primary" @click="handWritTransform">转换</el-button>
  364. </template>
  365. </hc-dialog>
  366. </hc-drawer>
  367. </template>
  368. <script setup>
  369. import { computed, nextTick, ref, watch } from 'vue'
  370. import { useClick } from 'hc-vue3-ui'
  371. import {
  372. arrIndex, deepClone, getArrValue, getObjVal,
  373. getObjValue, getRandom, isArray, isNullES, isString,
  374. } from 'js-fast-way'
  375. import { ElMessageBox } from 'element-plus'
  376. import { VueTagsInput } from '@vojtechlanka/vue-tags-input'
  377. import draggable from 'vuedraggable'
  378. //辅助解析文件
  379. import { rangeToString } from './formula/rangeToString'
  380. import { formulaArrayToString } from './formula/formulaArrayToString'
  381. import { formulaStringToArray } from './formula/formulaStringToArray'
  382. //接口文件
  383. import projectApi from '~api/project/project'
  384. import contractApi from '~api/project/contract'
  385. import formulaApi from '~api/project/formula'
  386. import elementApi from '~api/project/element'
  387. import privateApi from '~api/wbs/private'
  388. import treeApi from '~api/wbs/tree'
  389. const props = defineProps({
  390. data: {
  391. type: Object,
  392. default: () => ({}),
  393. },
  394. })
  395. //事件
  396. const emit = defineEmits(['close', 'finish', 'uncheck'])
  397. //双向绑定
  398. const isShow = defineModel('modelValue', {
  399. default: false,
  400. })
  401. //监听数据
  402. const dataInfo = ref(props.data)
  403. watch(() => props.data, (data) => {
  404. dataInfo.value = getObjValue(data)
  405. }, { immediate: true, deep: true })
  406. //监听显示
  407. watch(isShow, (val) => {
  408. if (val) getDataApi()
  409. })
  410. //基础变量
  411. const symbolReg = /(\+|-|\*|\/)(.+)/ //加减乘除
  412. const operatorReg = /^\+|-|\*|%/ //加减乘除
  413. const startFCRegExp = /^FC\.([a-zA-Z\d]+)\(/ //匹配开始的FC.xxx(
  414. const isScrollBar = ref(true)
  415. //获取数据
  416. const getDataApi = async () => {
  417. console.log(dataInfo.value)
  418. await getTypeMapApi()
  419. await getWbsFormElementData()
  420. await getFormulaStringToArrayApi()
  421. getProjectDataApi().then()
  422. }
  423. //保留位数
  424. const isRetain = ref(false)
  425. const retainNum = ref(2)
  426. //把公式文本还原数组
  427. const rightDict = ref([])
  428. const formulaId = ref('')
  429. const deviationRangeObj = ref({})
  430. const getFormulaStringToArrayApi = async () => {
  431. const { eleId, globalType, nodeId, pid } = getObjValue(dataInfo.value)
  432. const { code, data } = await formulaApi.detail({
  433. projectId: pid,
  434. elementId: eleId,
  435. nodeId: nodeId,
  436. scope: globalType,
  437. })
  438. if (code !== 200) return
  439. const res = getObjValue(data)
  440. console.log(res)
  441. if (!isNullES(res.id)) {
  442. //获取右边元素的字典
  443. let dictMap = getObjValue(res.dict), dictArr = []
  444. //遍历
  445. for (let i in dictMap) {
  446. dictArr.push(dictMap[i])
  447. }
  448. rightDict.value = dictArr
  449. formulaId.value = res.id
  450. //把公式字符串还原成数组
  451. let formula = formulaStringToArray(res.formula, res.map, formulaMenuMap.value)
  452. processFormula.value = getArrValue(formula?.processFormula)
  453. const results = resultFormula.value
  454. formula.resultFormula[0].id = results[0].id
  455. formula.resultFormula[0].name = results[0].name
  456. formula.resultFormula[0].tableElementKey = results[0].tableElementKey
  457. resultFormula.value[0].children = formula.resultFormula[0].children
  458. //允许偏差值范围
  459. let mapObj = JSON.parse(res.map)
  460. if (mapObj.deviationRangeJson) {
  461. deviationRangeObj.value = JSON.parse(mapObj.deviationRangeJson)
  462. }
  463. }
  464. if (res.scale >= 0) {
  465. isRetain.value = true
  466. retainNum.value = res.scale
  467. } else {
  468. isRetain.value = false
  469. retainNum.value = 2
  470. }
  471. }
  472. //获取当前元素的表名
  473. const getItemTableName = (item) => {
  474. if (item.type !== 'Element') {
  475. return
  476. }
  477. rightDict.value.forEach((ele) => {
  478. if (ele.ekey === item.tableElementKey) {
  479. item.tableName = ele.tableName
  480. }
  481. })
  482. }
  483. //允许偏差值范围
  484. const deviationRangeShow = ref(false)
  485. const setDeviationRange = () => {
  486. if (isResetFun.value) {
  487. window?.$message.warning('请先关闭重置函数')
  488. return
  489. }
  490. const val = !deviationRangeShow.value
  491. deviationRangeShow.value = val
  492. if (val) {
  493. const { symbol, model, arguments1, arguments2 } = deviationRangeObj.value
  494. deviationRangeSymbol.value = symbol
  495. deviationRangeResult.value = model
  496. curRangeFocusIndex.value = 1
  497. //公式
  498. if (isArray(arguments1) && arguments1.length > 1 || isArray(arguments2) && arguments2.length > 1) {
  499. //selectEleFormula.value = arguments1
  500. selectEleFormula3.value = arguments1
  501. selectEleFormula4.value = arguments2
  502. return
  503. }
  504. //参数1
  505. if (isString(arguments1)) {
  506. deviationRangeTag1.value = arguments1
  507. } else {
  508. deviationRangeTags1.value = arguments1
  509. }
  510. //参数2
  511. if (isString(arguments2)) {
  512. deviationRangeTag2.value = arguments2
  513. } else {
  514. deviationRangeTags2.value = arguments2
  515. }
  516. } else {
  517. curRangeFocusIndex.value = 0
  518. }
  519. }
  520. //获取顶部菜单数据
  521. const formulaMenuMap = ref({})
  522. const formulaMenuIndex = ref(null)
  523. const formulaMenuList = ref({})
  524. const getTypeMapApi = async () => {
  525. const { data } = await formulaApi.getTypeMap()
  526. const res = getObjValue(data)
  527. formulaMenuList.value = deepClone(res)
  528. //生成map,方便查找
  529. for (let key in res) {
  530. if (typeof(res[key]) === 'object') {
  531. res[key].forEach((formula)=>{
  532. formula.template = JSON.parse(formula.template)
  533. if (operatorReg.test(formula.template.ft)) {
  534. formulaMenuMap.value[formula.template.ft] = formula
  535. } else if (startFCRegExp.test(formula.template.ft)) {
  536. let regRes = formula.template.ft.match(startFCRegExp)
  537. formulaMenuMap.value[regRes[0]] = formula
  538. }
  539. })
  540. }
  541. }
  542. }
  543. //菜单被选择
  544. const equationSelectEleCopy = ref({})
  545. const handleFormulaMenu = async (index, path) => {
  546. if (isResetFun.value) {
  547. //重置函数
  548. if (path[0] !== '基础运算') {
  549. window?.$message.warning('当前只能使用基础运算')
  550. return
  551. }
  552. try {
  553. let indexs = Number(path[1].split('-')[1]) - 1
  554. const item = formulaMenuList.value[path[0]][indexs]
  555. const val = symbolReg.exec(item.name)[1]
  556. resetFunOperator(val)
  557. } catch (e) {
  558. console.error(e)
  559. }
  560. } else {
  561. await equationSelect(path)
  562. //深拷贝数据
  563. equationSelectEleCopy.value = deepClone(equationSelectEle.value)
  564. }
  565. }
  566. //在等式模式下点选计算式
  567. const equationSelectIndex = ref(-1)
  568. const equationSelect = async (path) => {
  569. const selectEle = getObjVal(equationSelectEle.value)
  570. if (!selectEle || !['Element', 'ParamData'].includes(selectEle.type)) {
  571. window?.$message.warning('请先选中元素')
  572. return
  573. }
  574. let obj = {}
  575. try {
  576. const index = Number(path[1].split('-')[1]) - 1
  577. const expression = formulaMenuList.value[path[0]][index]
  578. obj = deepClone(expression)
  579. obj.template = isNullES(obj.template) ? {} : JSON.parse(obj.template)
  580. } catch (error) {
  581. console.log(error)
  582. }
  583. if (obj.type === 1) return
  584. obj.arguments = new Array(obj.template.args.length)
  585. let ele = {}
  586. if (selectEle.type === 'ParamData') {
  587. ele = {
  588. type: 'ParamData',
  589. id: selectEle.id,
  590. v: selectEle.v,
  591. k: selectEle.k,
  592. name: selectEle.name,
  593. selected: false,
  594. }
  595. } else {
  596. ele = {
  597. type: 'Element',
  598. id: selectEle.id,
  599. name: selectEle.name,
  600. selected: false,
  601. tableElementKey: selectEle.tableElementKey,
  602. }
  603. }
  604. let tg = obj.template.args.findIndex(x => x.m !== '常量')
  605. obj.arguments[tg] = ele
  606. equationSelectEle.value.children.push(obj)
  607. //跳转到最新的标签
  608. equationSelectIndex.value = equationSelectEle.value.children.length - 1
  609. }
  610. //移除挂载的函数
  611. const delEquationSelect = (name) => {
  612. console.log(name)
  613. }
  614. //切换公式tab标签
  615. const leaveEquationSelect = (name, oldName) => {
  616. console.log(name, oldName)
  617. }
  618. //获取数据
  619. const resultFormula = ref([])
  620. const getWbsFormElementData = async () => {
  621. const { eleId } = getObjValue(dataInfo.value)
  622. resultFormula.value = []
  623. if (isNullES(eleId)) return
  624. const { data } = await elementApi.detail(eleId)
  625. const obj = getObjValue(data)
  626. resultFormula.value = [{
  627. type: 'Element',
  628. name: obj.eName,
  629. id: obj.id,
  630. selected: false,
  631. tableElementKey: obj.tableElementKey,
  632. children: [],
  633. }]
  634. }
  635. //左边被点击
  636. const processIndex = ref(-1)
  637. const processType = ref('')
  638. const resultFormulaItem = (item, index) => {
  639. clearResetFunClick()
  640. //设置当前选中
  641. processIndex.value = index
  642. processType.value = 'resultFormula'
  643. item.selected = true
  644. }
  645. //右边被点击
  646. const processFormulaItem = (item, index) => {
  647. clearResetFunClick()
  648. //设置当前选中
  649. processIndex.value = index
  650. processType.value = 'processFormula'
  651. item.selected = true
  652. }
  653. //清除选择
  654. const clearResetFunClick = () => {
  655. //清除左边的选中
  656. resultFormula.value.forEach((obj) => {
  657. obj.selected = false
  658. })
  659. //清除右边的选中
  660. processFormula.value.forEach((obj) => {
  661. obj.selected = false
  662. })
  663. //设置当前选中
  664. processIndex.value = -1
  665. processType.value = ''
  666. }
  667. //获取当前选中的元素
  668. const equationSelectEle = computed(() => {
  669. const type = processType.value
  670. if (isNullES(type)) return null
  671. const index = processIndex.value
  672. let arr = []
  673. if (type === 'resultFormula') {
  674. arr = resultFormula.value
  675. } else if (type === 'processFormula') {
  676. arr = processFormula.value
  677. }
  678. if (arr.length <= 0) return null
  679. return arr[index]
  680. })
  681. const isSelectEle = computed(() => {
  682. if (isNullES(equationSelectEle.value)) return false
  683. if (isNullES(equationSelectEle.value.children)) return false
  684. return equationSelectEle.value.children.length > 0
  685. })
  686. //是否有滚动条
  687. watch(isSelectEle, (newVal) => {
  688. isScrollBar.value = !newVal
  689. })
  690. //是否重置函数
  691. const isResetFun = ref(false)
  692. const resetFunClick = () => {
  693. if (deviationRangeShow.value) {
  694. window?.$message.warning('请先关闭允许偏差值范围')
  695. return
  696. }
  697. const val = !isResetFun.value
  698. if (val) {
  699. curRangeFocusIndex.value = 99
  700. } else {
  701. curRangeFocusIndex.value = 0
  702. }
  703. isResetFun.value = val
  704. isScrollBar.value = !val
  705. }
  706. //tree树配置
  707. const defaultProps = {
  708. label: 'title',
  709. children: 'children',
  710. isLeaf: (data) => {
  711. return !data.hasChildren
  712. },
  713. }
  714. //重置函数懒加载树
  715. const treeResetFunLazyRef = ref(null)
  716. const treeRangeSelectLazyRef = ref(null)
  717. const treeResetFunAllRef = ref(null)
  718. const treeRangeSelectAllRef = ref(null)
  719. const treeResetFunLazyExpanded = ref([])
  720. //获取重置函数懒加载树的数据
  721. const treeResetFunLoading = ref(false)
  722. const treeResetFunLazyLoad = async (node, resolve) => {
  723. const { level, data } = node
  724. treeResetFunItemData.value = data
  725. let parentId = level !== 0 ? data.id : 12345678910
  726. const { eleType, node: dataNode, tableType } = getObjValue(dataInfo.value)
  727. const treeNode = getObjValue(dataNode)
  728. if (level === 0) treeResetFunLoading.value = true
  729. if (!eleType) {
  730. //获取接口数据
  731. const { data } = await privateApi.tabTypeLazyTreeAll({
  732. parentId,
  733. current: 1,
  734. size: 99999,
  735. hasPartFormula: treeNode.hasPartFormula,
  736. })
  737. const res = getArrValue(data.records)
  738. treeResetFunLoading.value = false
  739. resolve(res)
  740. //处理返回的数据
  741. await nextTick()
  742. //处理展开
  743. try {
  744. const expandId = tableType ? Number(treeNode.tableType) - 1 : Number(treeNode.parentId) - 1
  745. if (!isNullES(expandId) && expandId >= 0) node.childNodes[expandId].expand()
  746. } catch { /* empty */ }
  747. //处理选中
  748. try {
  749. const paramsId = treeNode.initTableId
  750. if (!isNullES(paramsId)) {
  751. treeResetFunLazyRef.value?.setCurrentKey(paramsId)
  752. treeRangeSelectLazyRef.value?.setCurrentKey(paramsId)
  753. }
  754. } catch { /* empty */ }
  755. //获取节点详情
  756. await getNodeDetailApi(treeNode)
  757. } else if (eleType) {
  758. resolve([])
  759. }
  760. }
  761. //重置函数懒加载树点击
  762. const treeResetFunItemData = ref({})
  763. const treeResetFunNodeData = ref({})
  764. const treeResetFunLazyClick = async (data, node) => {
  765. treeResetFunItemData.value = data
  766. treeResetFunNodeData.value = node
  767. await getNodeDetailApi(data)
  768. }
  769. //重置函数树搜索
  770. const resetFunTree = ref('')
  771. const resetFunTreeAll = ref([])
  772. const isResetFunTreeLazy = ref(true)
  773. const resetFunTreeSearch = async () => {
  774. if (isNullES(resetFunTree.value)) {
  775. isResetFunTreeLazy.value = true
  776. return
  777. }
  778. isResetFunTreeLazy.value = false
  779. treeResetFunLoading.value = true
  780. const obj = treeResetFunItemData.value
  781. const parentId = obj.hasChildren ? obj.id : ''
  782. const { data, code } = await privateApi.tabTypeLazyTreeAll({
  783. parentId: parentId,
  784. current:1,
  785. size:1000,
  786. titleName: resetFunTree.value,
  787. })
  788. if (code !== 200) {
  789. resetFunTreeAll.value = []
  790. treeResetFunLoading.value = false
  791. return
  792. }
  793. resetFunTreeAll.value = getArrValue(data?.records)
  794. treeResetFunLoading.value = false
  795. }
  796. //重置函数元素搜索
  797. const resetFunEle = ref('')
  798. const isResetFunEleLoading = ref(false)
  799. const resetFunEleSearch = async () => {
  800. const { initTableId } = treeResetFunItemData.value
  801. if (isNullES(initTableId)) {
  802. resetFunEleData.value = []
  803. isResetFunEleLoading.value = false
  804. return
  805. }
  806. isResetFunEleLoading.value = true
  807. if (isNullES(resetFunEle.value)) {
  808. const { data } = await treeApi.getTableElments({
  809. id: initTableId,
  810. })
  811. resetFunEleData.value = getArrValue(data)
  812. } else {
  813. const { data } = await treeApi.getTableElments({
  814. id: initTableId,
  815. search: resetFunEle.value,
  816. })
  817. resetFunEleData.value = getArrValue(data)
  818. }
  819. isResetFunEleLoading.value = false
  820. }
  821. //获取节点详情
  822. const resetFunEleData = ref([])
  823. const getNodeDetailApi = async (item) => {
  824. await useClick(300)
  825. if (isNullES(item.initTableId)) {
  826. resetFunEleData.value = []
  827. isResetFunEleLoading.value = false
  828. return
  829. }
  830. if (item.hasChildren === false || item.isLinkTable === 2) {
  831. isResetFunEleLoading.value = true
  832. const { data } = await treeApi.getTableElments({
  833. id: item.initTableId,
  834. })
  835. resetFunEleData.value = getArrValue(data)
  836. } else {
  837. resetFunEleData.value = []
  838. }
  839. isResetFunEleLoading.value = false
  840. }
  841. //元素字段被点击
  842. const selectEleFormula = ref([])
  843. const selectEleFormula3 = ref([])
  844. const selectEleFormula4 = ref([])
  845. const resetFunEleTagClick = (item) => {
  846. const index = curRangeFocusIndex.value
  847. if (index <= 0) {
  848. window?.$message.warning('非正常操作')
  849. return
  850. }
  851. let arr = []
  852. if (index === 99) {
  853. //重置函数
  854. arr = selectEleFormula.value
  855. } else if (index === 3) {
  856. //参数1
  857. arr = selectEleFormula3.value
  858. } else if (index === 4) {
  859. //参数2
  860. arr = selectEleFormula4.value
  861. }
  862. let { type, name } = getObjValue(arr[arr.length - 1])
  863. if (type === 'Text') {
  864. window?.$message.warning('元素无法连续出现在输入值后面')
  865. return
  866. }
  867. if (type === 'Brackets' && name === ')') {
  868. window?.$message.warning('元素无法连续出现在右括号后面')
  869. return
  870. }
  871. if (arr.length === 0 || ['Operator', 'Brackets'].includes(type) || name === '(') {
  872. if (!isNullES(item.tableElementKey)) {
  873. const obj = {
  874. type: 'Element',
  875. name: item.eName,
  876. id: item.id,
  877. selected: false,
  878. tableElementKey: item.tableElementKey,
  879. index: getRandom(5),
  880. children: [],
  881. }
  882. if (index === 99) {
  883. selectEleFormula.value.push(obj)
  884. } else if (index === 3) {
  885. selectEleFormula3.value.push(obj)
  886. } else if (index === 4) {
  887. selectEleFormula4.value.push(obj)
  888. }
  889. }
  890. } else {
  891. window?.$message.warning('当前操作不符合要求')
  892. }
  893. }
  894. //输入弹窗
  895. const promptMessageBox = async () => {
  896. return new Promise(resolve => {
  897. ElMessageBox.prompt('', '请输入值', {
  898. confirmButtonText: '确定',
  899. cancelButtonText: '取消',
  900. inputErrorMessage: '请输入内容',
  901. inputValidator: (value) => {
  902. return !isNullES(value)
  903. },
  904. }).then(({ value }) => {
  905. resolve(value)
  906. }).catch(() => {
  907. resolve()
  908. })
  909. })
  910. }
  911. //输入值
  912. const resetFunText = async () => {
  913. const val = await promptMessageBox()
  914. if (isNullES(val)) return
  915. const index = curRangeFocusIndex.value
  916. if (index <= 0) {
  917. window?.$message.warning('非正常操作')
  918. return
  919. }
  920. //获取数组
  921. let arr = []
  922. if (index === 99) {
  923. //重置函数
  924. arr = selectEleFormula.value
  925. } else if (index === 3) {
  926. //参数1
  927. arr = selectEleFormula3.value
  928. } else if (index === 4) {
  929. //参数2
  930. arr = selectEleFormula4.value
  931. }
  932. if (arr.length > 0) {
  933. let { type, name } = getObjValue(arr[arr.length - 1])
  934. if (type === 'Element') {
  935. window?.$message.warning('输入值无法连续出现在元素后面')
  936. return
  937. }
  938. if (type === 'Text') {
  939. window?.$message.warning('输入值无法连续出现在输入值后面')
  940. return
  941. }
  942. if (type === 'Brackets' && name === ')') {
  943. window?.$message.warning('输入值无法连续出现在右括号后面')
  944. return
  945. }
  946. }
  947. //公共对象
  948. const obj = {
  949. type: 'Text',
  950. name: val,
  951. selected: false,
  952. index: getRandom(5),
  953. }
  954. if (index === 99) {
  955. selectEleFormula.value.push(obj)
  956. } else if (index === 3) {
  957. selectEleFormula3.value.push(obj)
  958. } else if (index === 4) {
  959. selectEleFormula4.value.push(obj)
  960. }
  961. }
  962. //括号
  963. const resetFunBrackets = (val) => {
  964. const index = curRangeFocusIndex.value
  965. if (index <= 0) {
  966. window?.$message.warning('非正常操作')
  967. return
  968. }
  969. //公共对象
  970. const obj = {
  971. type: 'Brackets',
  972. name: val,
  973. selected: false,
  974. index: getRandom(5),
  975. }
  976. if (index === 99) {
  977. //重置函数
  978. selectEleFormula.value.push(obj)
  979. } else if (index === 3) {
  980. //参数1
  981. selectEleFormula3.value.push(obj)
  982. } else if (index === 4) {
  983. //参数2
  984. selectEleFormula4.value.push(obj)
  985. }
  986. }
  987. //运算符
  988. const resetFunOperator = (val) => {
  989. const index = curRangeFocusIndex.value
  990. if (index <= 0) {
  991. window?.$message.warning('非正常操作')
  992. return
  993. }
  994. //获取数组
  995. let arr = []
  996. if (index === 99) {
  997. //重置函数
  998. arr = selectEleFormula.value
  999. } else if (index === 3) {
  1000. //参数1
  1001. arr = selectEleFormula3.value
  1002. } else if (index === 4) {
  1003. //参数2
  1004. arr = selectEleFormula4.value
  1005. }
  1006. const map = formulaMenuMap.value
  1007. if (arr.length <= 0) {
  1008. window?.$message.warning('公式开头不能是运算符号')
  1009. return
  1010. }
  1011. let { type, name } = getObjValue(arr[arr.length - 1])
  1012. if (type === 'Operator') {
  1013. window?.$message.warning('运算符号无法连续出现在运算符号后面')
  1014. return
  1015. }
  1016. if (type === 'Brackets' && name === '(') {
  1017. window?.$message.warning('运算符号无法连续出现在左括号后面')
  1018. return
  1019. }
  1020. const obj = getObjValue(map[val])
  1021. //公共对象
  1022. const data = {
  1023. type: 'Operator',
  1024. name: symbolReg.exec(obj.name)[1],
  1025. selected: false,
  1026. template: obj.template,
  1027. index: getRandom(5),
  1028. }
  1029. if (index === 99) {
  1030. selectEleFormula.value.push(data)
  1031. } else if (index === 3) {
  1032. selectEleFormula3.value.push(data)
  1033. } else if (index === 4) {
  1034. selectEleFormula4.value.push(data)
  1035. }
  1036. }
  1037. //删除
  1038. const resetFunDel = () => {
  1039. const index = curRangeFocusIndex.value
  1040. if (index <= 0) {
  1041. window?.$message.warning('非正常操作')
  1042. return
  1043. }
  1044. //获取数组
  1045. let arr = []
  1046. if (index === 99) {
  1047. //重置函数
  1048. arr = selectEleFormula.value
  1049. } else if (index === 3) {
  1050. //参数1
  1051. arr = selectEleFormula3.value
  1052. } else if (index === 4) {
  1053. //参数2
  1054. arr = selectEleFormula4.value
  1055. }
  1056. const newArr = deepClone(arr)
  1057. if (newArr.length <= 0) {
  1058. window?.$message.warning('请先添加相关元素')
  1059. return
  1060. }
  1061. const indexs = arrIndex(newArr, 'selected', true)
  1062. if (indexs !== -1) {
  1063. newArr.splice(indexs, 1)
  1064. if (index === 99) {
  1065. selectEleFormula.value = newArr
  1066. } else if (index === 3) {
  1067. selectEleFormula3.value = newArr
  1068. } else if (index === 4) {
  1069. selectEleFormula4.value = newArr
  1070. }
  1071. } else {
  1072. newArr.splice(newArr.length - 1, 1)
  1073. if (index === 99) {
  1074. selectEleFormula.value = newArr
  1075. } else if (index === 3) {
  1076. selectEleFormula3.value = newArr
  1077. } else if (index === 4) {
  1078. selectEleFormula4.value = newArr
  1079. }
  1080. }
  1081. }
  1082. //清空
  1083. const resetFunClear = () => {
  1084. const index = curRangeFocusIndex.value
  1085. if (index <= 0) {
  1086. window?.$message.warning('非正常操作')
  1087. return
  1088. }
  1089. if (index === 99) {
  1090. //重置函数
  1091. selectEleFormula.value = []
  1092. } else if (index === 3) {
  1093. //参数1
  1094. selectEleFormula3.value = []
  1095. } else if (index === 4) {
  1096. //参数2
  1097. selectEleFormula4.value = []
  1098. }
  1099. }
  1100. //被点击
  1101. const selectEleFormulaItem = (item) => {
  1102. const index = curRangeFocusIndex.value
  1103. if (index <= 0) {
  1104. window?.$message.warning('非正常操作')
  1105. return
  1106. }
  1107. //获取数组
  1108. let arr = []
  1109. if (index === 99) {
  1110. //重置函数
  1111. arr = selectEleFormula.value
  1112. } else if (index === 3) {
  1113. //参数1
  1114. arr = selectEleFormula3.value
  1115. } else if (index === 4) {
  1116. //参数2
  1117. arr = selectEleFormula4.value
  1118. }
  1119. for (let i = 0; i < arr.length; i++) {
  1120. if (item.index === arr[i].index) {
  1121. arr[i].selected = !arr[i].selected
  1122. } else {
  1123. arr[i].selected = false
  1124. }
  1125. }
  1126. if (index === 99) {
  1127. selectEleFormula.value = arr
  1128. } else if (index === 3) {
  1129. selectEleFormula3.value = arr
  1130. } else if (index === 4) {
  1131. selectEleFormula4.value = arr
  1132. }
  1133. }
  1134. //赋值给等号右边的数组
  1135. const processFormula = ref([])
  1136. const setProcessFormula = () => {
  1137. const arr = selectEleFormula.value
  1138. let leftNum = 0, rightNum = 0
  1139. arr.forEach(({ type, name }) => {
  1140. if (type === 'Brackets') {
  1141. if (name === '(') {
  1142. leftNum++
  1143. } else if (name === ')') {
  1144. rightNum++
  1145. }
  1146. }
  1147. })
  1148. if (leftNum !== rightNum) {
  1149. window?.$message.warning('左右括号数量不相等,请先检查是否正确')
  1150. return
  1151. }
  1152. processFormula.value = deepClone(arr)
  1153. isResetFun.value = false
  1154. isScrollBar.value = true
  1155. }
  1156. //获取项目数据
  1157. const projectId = ref('')
  1158. const projectList = ref([])
  1159. const getProjectDataApi = async () => {
  1160. const { data } = await projectApi.page({
  1161. current: 1,
  1162. size: 99999,
  1163. })
  1164. projectList.value = getArrValue(data?.records)
  1165. }
  1166. //项目被选择
  1167. const contractId = ref('')
  1168. const contractList = ref([])
  1169. const projectChange = async () => {
  1170. contractId.value = ''
  1171. const { data } = await contractApi.getList(projectId.value)
  1172. contractList.value = getArrValue(data)
  1173. }
  1174. //项目查询
  1175. const projectQueryClick = () => {
  1176. console.log('原来就没做这个功能')
  1177. }
  1178. //允许偏差值范围
  1179. const deviationRangeSymbol = ref('【min,max】')
  1180. //模式切换
  1181. const deviationRangeResult = ref('1')
  1182. const deviationRangeResultChange = () => {
  1183. if (deviationRangeResult.value === '1') {
  1184. if (!['<', '≤'].includes(deviationRangeSymbol.value)) {
  1185. curRangeFocusIndex.value = 1
  1186. } else if (!['>', '≥'].includes(deviationRangeSymbol.value)) {
  1187. curRangeFocusIndex.value = 2
  1188. }
  1189. } else if (deviationRangeResult.value === '2') {
  1190. if (!['<', '≤'].includes(deviationRangeSymbol.value)) {
  1191. curRangeFocusIndex.value = 3
  1192. } else if (!['>', '≥'].includes(deviationRangeSymbol.value)) {
  1193. curRangeFocusIndex.value = 4
  1194. }
  1195. }
  1196. }
  1197. //允许偏差值范围1
  1198. const deviationRangeTag1 = ref('')
  1199. const deviationRangeTags1 = ref([])
  1200. const deviationRangeBlur1 = () => {
  1201. if (deviationRangeTag1.value) {
  1202. if (deviationRangeTag1.value && deviationRangeTags1.value[0]) {
  1203. emit('uncheck', deviationRangeTags1.value[0].id)
  1204. }
  1205. deviationRangeTags1.value = []
  1206. }
  1207. }
  1208. //允许偏差值范围2
  1209. const deviationRangeTag2 = ref('')
  1210. const deviationRangeTags2 = ref([])
  1211. const deviationRangeBlur2 = () => {
  1212. if (deviationRangeTag2.value) {
  1213. if (deviationRangeTag2.value && deviationRangeTags2.value[0]) {
  1214. emit('uncheck', deviationRangeTags2.value[0].id)
  1215. }
  1216. deviationRangeTags2.value = []
  1217. }
  1218. }
  1219. //当前在哪个输入框
  1220. const curRangeFocusIndex = ref(0)
  1221. const rangeAddingTag = () => {
  1222. console.log('原来的版本就啥也没做')
  1223. }
  1224. //选择参数
  1225. const isRangeSelectEle = ref(false)
  1226. const deviationRangeSelectEle = () => {
  1227. const val = !isRangeSelectEle.value
  1228. isRangeSelectEle.value = val
  1229. isScrollBar.value = !val
  1230. }
  1231. //手写模式
  1232. const handWritText = ref('')
  1233. const handWritEleMap = ref({})
  1234. const isHandWritEle = ref(false)
  1235. const handWritClick = () => {
  1236. try {
  1237. let { text, eleMap } = formulaArrayToString(processFormula.value, resultFormula.value)
  1238. handWritText.value = text
  1239. handWritEleMap.value = JSON.stringify(eleMap)
  1240. isHandWritEle.value = true
  1241. } catch (error) {
  1242. console.log(error)
  1243. window?.$message.error('生成公式文本失败')
  1244. }
  1245. }
  1246. //手写模式转换
  1247. const handWritTransform = () => {
  1248. try {
  1249. let formula = formulaStringToArray(handWritText.value, handWritEleMap.value, formulaMenuMap.value)
  1250. processFormula.value = getArrValue(formula.processFormula)
  1251. const results = resultFormula.value
  1252. formula.resultFormula[0].id = results[0].id
  1253. formula.resultFormula[0].name = results[0].name
  1254. formula.resultFormula[0].tableElementKey = results[0].tableElementKey
  1255. resultFormula.value[0].children = formula.resultFormula[0].children
  1256. handWritEleClose()
  1257. } catch (error) {
  1258. console.log(error)
  1259. window?.$message.error('转成配置用的数组失败')
  1260. }
  1261. }
  1262. //手写模式关闭
  1263. const handWritEleClose = () => {
  1264. isHandWritEle.value = false
  1265. handWritText.value = ''
  1266. handWritEleMap.value = {}
  1267. }
  1268. const findNumber = (array) => {
  1269. for (const item of array) {
  1270. if (!item.children) continue
  1271. const child = item.children.find(child => child.number)
  1272. if (child) return child.number
  1273. }
  1274. return ''
  1275. }
  1276. //获取元素
  1277. const getTemplateFt = (item) => {
  1278. let template = item?.template?.ft
  1279. item.template.args.forEach(obj => {
  1280. template = template.replace(obj.key, obj.m)
  1281. })
  1282. //item.arguments[0].tableElementKey = item.arguments[0].tableElementKey.replace('_key', ':key')
  1283. return template
  1284. }
  1285. //输入文本
  1286. const enterTextClick = (item, indexs) => {
  1287. item.arguments[indexs] = ''
  1288. }
  1289. //选择元素
  1290. const elementsArgumenItem = ref({})
  1291. const selectingElements = (item, indexs) => {
  1292. elementsArgumenItem.value = {
  1293. arguments: item.arguments,
  1294. index: indexs,
  1295. }
  1296. }
  1297. //当前元素
  1298. const setCurElement = (item, index, indexs) => {
  1299. let tmp = deepClone(equationSelectEleCopy.value)
  1300. tmp['tableElementKey'] = tmp['tableElementKey'].replace('_key', ':key')
  1301. item.arguments[indexs] = tmp.children[index].arguments[indexs]
  1302. }
  1303. //保存
  1304. const submitLoading = ref(false)
  1305. const submitClick = async () => {
  1306. if (isResetFun.value) {
  1307. //重置函数
  1308. setProcessFormula()
  1309. } else {
  1310. //允许偏差值范围
  1311. submitLoading.value = true
  1312. const result = deviationRangeResult.value
  1313. deviationRangeObj.value = {
  1314. symbol: deviationRangeSymbol.value,
  1315. model: result,
  1316. arguments1: result === '2' ? selectEleFormula3.value : deviationRangeTag1.value,
  1317. arguments2: result === '2' ? selectEleFormula4.value : deviationRangeTag2.value,
  1318. }
  1319. //处理数据
  1320. const process = processFormula.value, results = resultFormula.value
  1321. let obj = formulaArrayToString(process, results)
  1322. let deviationRangeText = rangeToString(deviationRangeObj.value, obj.eleMap)
  1323. obj.eleMap.deviationRangeJson = JSON.stringify(deviationRangeObj.value)
  1324. //特殊公式会有number
  1325. let number = findNumber(process) || findNumber(results)
  1326. //发起请求
  1327. const { eleId, globalType, nodeId, pid } = getObjValue(dataInfo.value)
  1328. const formData = {
  1329. formula: obj.text,
  1330. remark: '',
  1331. nodeId: nodeId,
  1332. elementId: eleId,
  1333. scale: isRetain.value ? retainNum.value : '',
  1334. number: number,
  1335. map: JSON.stringify(obj.eleMap),
  1336. scope: globalType,
  1337. projectId: projectId.value || pid,
  1338. dev: deviationRangeText,
  1339. }
  1340. let res = {}
  1341. if (isNullES(formulaId.value)) {
  1342. //新增
  1343. res = await formulaApi.save({ ...formData, ver:1 })
  1344. } else {
  1345. //更新
  1346. res = await formulaApi.update({ id: formulaId.value, ...formData })
  1347. }
  1348. const { code, msg, data } = getObjValue(res)
  1349. if (code !== 200) {
  1350. submitLoading.value = false
  1351. return
  1352. }
  1353. let msgStr = '保存成功'
  1354. if (msg === '公式已删除') {
  1355. formulaId.value = ''
  1356. msgStr = msg
  1357. } else if (!isNullES(data)) {
  1358. formulaId.value = data
  1359. }
  1360. window?.$message.success(msgStr)
  1361. getFormulaStringToArrayApi()
  1362. submitLoading.value = false
  1363. }
  1364. }
  1365. //关闭抽屉
  1366. const drawerClose = () => {
  1367. if (isResetFun.value) {
  1368. //重置函数
  1369. isResetFun.value = false
  1370. isScrollBar.value = true
  1371. curRangeFocusIndex.value = 0
  1372. } else if (deviationRangeShow.value) {
  1373. //允许偏差值范围
  1374. deviationRangeShow.value = false
  1375. isRangeSelectEle.value = false
  1376. curRangeFocusIndex.value = 0
  1377. } else {
  1378. isShow.value = false
  1379. //重置元素
  1380. isResetFun.value = false
  1381. isScrollBar.value = true
  1382. //允许偏差值范围
  1383. deviationRangeShow.value = false
  1384. curRangeFocusIndex.value = 0
  1385. //选择的元素
  1386. selectEleFormula.value = []
  1387. selectEleFormula3.value = []
  1388. selectEleFormula4.value = []
  1389. //手写模式
  1390. isHandWritEle.value = false
  1391. handWritText.value = ''
  1392. handWritEleMap.value = {}
  1393. emit('close')
  1394. }
  1395. }
  1396. </script>
  1397. <style lang="scss">
  1398. @import '~src/styles/view/project/edit-formula';
  1399. </style>