edit-formula.vue 58 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461
  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, getObjValue,
  373. 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 handleFormulaMenu = (index, path) => {
  545. if (isResetFun.value) {
  546. //重置函数
  547. if (path[0] !== '基础运算') {
  548. window?.$message.warning('当前只能使用基础运算')
  549. return
  550. }
  551. try {
  552. let index = Number(path[1].split('-')[1]) - 1
  553. const item = formulaMenuList.value[path[0]][index]
  554. const val = symbolReg.exec(item.name)[1]
  555. resetFunOperator(val)
  556. } catch (e) {
  557. console.error(e)
  558. }
  559. } else {
  560. equationSelect(path)
  561. }
  562. }
  563. //在等式模式下点选计算式
  564. const equationSelectIndex = ref(-1)
  565. const equationSelect = (path) => {
  566. const selectEle = getObjVal(equationSelectEle.value)
  567. if (!selectEle || !['Element', 'ParamData'].includes(selectEle.type)) {
  568. window?.$message.warning('请先选中元素')
  569. return
  570. }
  571. console.log(selectEle)
  572. let obj = {}
  573. try {
  574. const index = Number(path[1].split('-')[1]) - 1
  575. const expression = formulaMenuList.value[path[0]][index]
  576. obj = deepClone(expression)
  577. } catch (error) {
  578. console.log(error)
  579. }
  580. if (obj.type === 1) return
  581. obj.arguments = new Array(obj.template.args.length)
  582. let ele = {}
  583. if (selectEle.type === 'ParamData') {
  584. ele = {
  585. type: 'ParamData',
  586. id: selectEle.id,
  587. v: selectEle.v,
  588. k: selectEle.k,
  589. name: selectEle.name,
  590. selected: false,
  591. }
  592. } else {
  593. ele = {
  594. type: 'Element',
  595. id: selectEle.id,
  596. name: selectEle.name,
  597. selected: false,
  598. tableElementKey: selectEle.tableElementKey,
  599. }
  600. }
  601. let tg = obj.template.args.findIndex(x => x.m !== '常量')
  602. obj.arguments[tg] = ele
  603. equationSelectEle.value.children.push(obj)
  604. console.log(equationSelectEle.value.children)
  605. //跳转到最新的标签
  606. equationSelectIndex.value = equationSelectEle.value.children.length - 1
  607. }
  608. //移除挂载的函数
  609. const delEquationSelect = (name) => {
  610. console.log(name)
  611. }
  612. //切换公式tab标签
  613. const leaveEquationSelect = (name, oldName) => {
  614. console.log(name, oldName)
  615. }
  616. //获取数据
  617. const resultFormula = ref([])
  618. const getWbsFormElementData = async () => {
  619. const { eleId } = getObjValue(dataInfo.value)
  620. resultFormula.value = []
  621. if (isNullES(eleId)) return
  622. const { data } = await elementApi.detail(eleId)
  623. const obj = getObjValue(data)
  624. resultFormula.value = [{
  625. type: 'Element',
  626. name: obj.eName,
  627. id: obj.id,
  628. selected: false,
  629. tableElementKey: obj.tableElementKey,
  630. children: [],
  631. }]
  632. }
  633. //左边被点击
  634. const processIndex = ref(-1)
  635. const processType = ref('')
  636. const resultFormulaItem = (item, index) => {
  637. clearResetFunClick()
  638. //设置当前选中
  639. processIndex.value = index
  640. processType.value = 'resultFormula'
  641. item.selected = true
  642. }
  643. //右边被点击
  644. const processFormulaItem = (item, index) => {
  645. clearResetFunClick()
  646. //设置当前选中
  647. processIndex.value = index
  648. processType.value = 'processFormula'
  649. item.selected = true
  650. }
  651. //清除选择
  652. const clearResetFunClick = () => {
  653. //清除左边的选中
  654. resultFormula.value.forEach((obj) => {
  655. obj.selected = false
  656. })
  657. //清除右边的选中
  658. processFormula.value.forEach((obj) => {
  659. obj.selected = false
  660. })
  661. //设置当前选中
  662. processIndex.value = -1
  663. processType.value = ''
  664. }
  665. //获取当前选中的元素
  666. const equationSelectEle = computed(() => {
  667. const type = processType.value
  668. if (isNullES(type)) return null
  669. const index = processIndex.value
  670. let arr = []
  671. if (type === 'resultFormula') {
  672. arr = resultFormula.value
  673. } else if (type === 'processFormula') {
  674. arr = processFormula.value
  675. }
  676. if (arr.length <= 0) return null
  677. return arr[index]
  678. })
  679. const isSelectEle = computed(() => {
  680. if (isNullES(equationSelectEle.value)) return false
  681. if (isNullES(equationSelectEle.value.children)) return false
  682. return equationSelectEle.value.children.length > 0
  683. })
  684. //是否有滚动条
  685. watch(isSelectEle, (newVal) => {
  686. isScrollBar.value = !newVal
  687. })
  688. //是否重置函数
  689. const isResetFun = ref(false)
  690. const resetFunClick = () => {
  691. if (deviationRangeShow.value) {
  692. window?.$message.warning('请先关闭允许偏差值范围')
  693. return
  694. }
  695. const val = !isResetFun.value
  696. if (val) {
  697. curRangeFocusIndex.value = 99
  698. } else {
  699. curRangeFocusIndex.value = 0
  700. }
  701. isResetFun.value = val
  702. isScrollBar.value = !val
  703. }
  704. //tree树配置
  705. const defaultProps = {
  706. label: 'title',
  707. children: 'children',
  708. isLeaf: (data) => {
  709. return !data.hasChildren
  710. },
  711. }
  712. //重置函数懒加载树
  713. const treeResetFunLazyRef = ref(null)
  714. const treeRangeSelectLazyRef = ref(null)
  715. const treeResetFunAllRef = ref(null)
  716. const treeRangeSelectAllRef = ref(null)
  717. const treeResetFunLazyExpanded = ref([])
  718. //获取重置函数懒加载树的数据
  719. const treeResetFunLoading = ref(false)
  720. const treeResetFunLazyLoad = async (node, resolve) => {
  721. const { level, data } = node
  722. treeResetFunItemData.value = data
  723. let parentId = level !== 0 ? data.id : 12345678910
  724. const { eleType, node: dataNode, tableType } = getObjValue(dataInfo.value)
  725. const treeNode = getObjValue(dataNode)
  726. if (level === 0) treeResetFunLoading.value = true
  727. if (!eleType) {
  728. //获取接口数据
  729. const { data } = await privateApi.tabTypeLazyTreeAll({
  730. parentId,
  731. current: 1,
  732. size: 99999,
  733. hasPartFormula: treeNode.hasPartFormula,
  734. })
  735. const res = getArrValue(data.records)
  736. treeResetFunLoading.value = false
  737. resolve(res)
  738. //处理返回的数据
  739. await nextTick()
  740. //处理展开
  741. try {
  742. const expandId = tableType ? Number(treeNode.tableType) - 1 : Number(treeNode.parentId) - 1
  743. if (!isNullES(expandId) && expandId >= 0) node.childNodes[expandId].expand()
  744. } catch { /* empty */ }
  745. //处理选中
  746. try {
  747. const paramsId = treeNode.initTableId
  748. if (!isNullES(paramsId)) {
  749. treeResetFunLazyRef.value?.setCurrentKey(paramsId)
  750. treeRangeSelectLazyRef.value?.setCurrentKey(paramsId)
  751. }
  752. } catch { /* empty */ }
  753. //获取节点详情
  754. await getNodeDetailApi(treeNode)
  755. } else if (eleType) {
  756. resolve([])
  757. }
  758. }
  759. //重置函数懒加载树点击
  760. const treeResetFunItemData = ref({})
  761. const treeResetFunNodeData = ref({})
  762. const treeResetFunLazyClick = async (data, node) => {
  763. treeResetFunItemData.value = data
  764. treeResetFunNodeData.value = node
  765. await getNodeDetailApi(data)
  766. }
  767. //重置函数树搜索
  768. const resetFunTree = ref('')
  769. const resetFunTreeAll = ref([])
  770. const isResetFunTreeLazy = ref(true)
  771. const resetFunTreeSearch = async () => {
  772. if (isNullES(resetFunTree.value)) {
  773. isResetFunTreeLazy.value = true
  774. return
  775. }
  776. isResetFunTreeLazy.value = false
  777. treeResetFunLoading.value = true
  778. const obj = treeResetFunItemData.value
  779. const parentId = obj.hasChildren ? obj.id : ''
  780. const { data, code } = await privateApi.tabTypeLazyTreeAll({
  781. parentId: parentId,
  782. current:1,
  783. size:1000,
  784. titleName: resetFunTree.value,
  785. })
  786. if (code !== 200) {
  787. resetFunTreeAll.value = []
  788. treeResetFunLoading.value = false
  789. return
  790. }
  791. resetFunTreeAll.value = getArrValue(data?.records)
  792. treeResetFunLoading.value = false
  793. }
  794. //重置函数元素搜索
  795. const resetFunEle = ref('')
  796. const isResetFunEleLoading = ref(false)
  797. const resetFunEleSearch = async () => {
  798. const { initTableId } = treeResetFunItemData.value
  799. if (isNullES(initTableId)) {
  800. resetFunEleData.value = []
  801. isResetFunEleLoading.value = false
  802. return
  803. }
  804. isResetFunEleLoading.value = true
  805. if (isNullES(resetFunEle.value)) {
  806. const { data } = await treeApi.getTableElments({
  807. id: initTableId,
  808. })
  809. resetFunEleData.value = getArrValue(data)
  810. } else {
  811. const { data } = await treeApi.getTableElments({
  812. id: initTableId,
  813. search: resetFunEle.value,
  814. })
  815. resetFunEleData.value = getArrValue(data)
  816. }
  817. isResetFunEleLoading.value = false
  818. }
  819. //获取节点详情
  820. const resetFunEleData = ref([])
  821. const getNodeDetailApi = async (item) => {
  822. await useClick(300)
  823. if (isNullES(item.initTableId)) {
  824. resetFunEleData.value = []
  825. isResetFunEleLoading.value = false
  826. return
  827. }
  828. if (item.hasChildren === false || item.isLinkTable === 2) {
  829. isResetFunEleLoading.value = true
  830. const { data } = await treeApi.getTableElments({
  831. id: item.initTableId,
  832. })
  833. resetFunEleData.value = getArrValue(data)
  834. } else {
  835. resetFunEleData.value = []
  836. }
  837. isResetFunEleLoading.value = false
  838. }
  839. //元素字段被点击
  840. const selectEleFormula = ref([])
  841. const selectEleFormula3 = ref([])
  842. const selectEleFormula4 = ref([])
  843. const resetFunEleTagClick = (item) => {
  844. const index = curRangeFocusIndex.value
  845. if (index <= 0) {
  846. window?.$message.warning('非正常操作')
  847. return
  848. }
  849. let arr = []
  850. if (index === 99) {
  851. //重置函数
  852. arr = selectEleFormula.value
  853. } else if (index === 3) {
  854. //参数1
  855. arr = selectEleFormula3.value
  856. } else if (index === 4) {
  857. //参数2
  858. arr = selectEleFormula4.value
  859. }
  860. let { type, name } = getObjValue(arr[arr.length - 1])
  861. if (type === 'Text') {
  862. window?.$message.warning('元素无法连续出现在输入值后面')
  863. return
  864. }
  865. if (type === 'Brackets' && name === ')') {
  866. window?.$message.warning('元素无法连续出现在右括号后面')
  867. return
  868. }
  869. if (arr.length === 0 || ['Operator', 'Brackets'].includes(type) || name === '(') {
  870. if (!isNullES(item.tableElementKey)) {
  871. const obj = {
  872. type: 'Element',
  873. name: item.eName,
  874. id: item.id,
  875. selected: false,
  876. tableElementKey: item.tableElementKey,
  877. index: getRandom(5),
  878. children: [],
  879. }
  880. if (index === 99) {
  881. selectEleFormula.value.push(obj)
  882. } else if (index === 3) {
  883. selectEleFormula3.value.push(obj)
  884. } else if (index === 4) {
  885. selectEleFormula4.value.push(obj)
  886. }
  887. }
  888. } else {
  889. window?.$message.warning('当前操作不符合要求')
  890. }
  891. }
  892. //输入弹窗
  893. const promptMessageBox = async () => {
  894. return new Promise(resolve => {
  895. ElMessageBox.prompt('', '请输入值', {
  896. confirmButtonText: '确定',
  897. cancelButtonText: '取消',
  898. inputErrorMessage: '请输入内容',
  899. inputValidator: (value) => {
  900. return !isNullES(value)
  901. },
  902. }).then(({ value }) => {
  903. resolve(value)
  904. }).catch(() => {
  905. resolve()
  906. })
  907. })
  908. }
  909. //输入值
  910. const resetFunText = async () => {
  911. const val = await promptMessageBox()
  912. if (isNullES(val)) return
  913. const index = curRangeFocusIndex.value
  914. if (index <= 0) {
  915. window?.$message.warning('非正常操作')
  916. return
  917. }
  918. //获取数组
  919. let arr = []
  920. if (index === 99) {
  921. //重置函数
  922. arr = selectEleFormula.value
  923. } else if (index === 3) {
  924. //参数1
  925. arr = selectEleFormula3.value
  926. } else if (index === 4) {
  927. //参数2
  928. arr = selectEleFormula4.value
  929. }
  930. if (arr.length > 0) {
  931. let { type, name } = getObjValue(arr[arr.length - 1])
  932. if (type === 'Element') {
  933. window?.$message.warning('输入值无法连续出现在元素后面')
  934. return
  935. }
  936. if (type === 'Text') {
  937. window?.$message.warning('输入值无法连续出现在输入值后面')
  938. return
  939. }
  940. if (type === 'Brackets' && name === ')') {
  941. window?.$message.warning('输入值无法连续出现在右括号后面')
  942. return
  943. }
  944. }
  945. //公共对象
  946. const obj = {
  947. type: 'Text',
  948. name: val,
  949. selected: false,
  950. index: getRandom(5),
  951. }
  952. if (index === 99) {
  953. selectEleFormula.value.push(obj)
  954. } else if (index === 3) {
  955. selectEleFormula3.value.push(obj)
  956. } else if (index === 4) {
  957. selectEleFormula4.value.push(obj)
  958. }
  959. }
  960. //括号
  961. const resetFunBrackets = (val) => {
  962. const index = curRangeFocusIndex.value
  963. if (index <= 0) {
  964. window?.$message.warning('非正常操作')
  965. return
  966. }
  967. //公共对象
  968. const obj = {
  969. type: 'Brackets',
  970. name: val,
  971. selected: false,
  972. index: getRandom(5),
  973. }
  974. if (index === 99) {
  975. //重置函数
  976. selectEleFormula.value.push(obj)
  977. } else if (index === 3) {
  978. //参数1
  979. selectEleFormula3.value.push(obj)
  980. } else if (index === 4) {
  981. //参数2
  982. selectEleFormula4.value.push(obj)
  983. }
  984. }
  985. //运算符
  986. const resetFunOperator = (val) => {
  987. const index = curRangeFocusIndex.value
  988. if (index <= 0) {
  989. window?.$message.warning('非正常操作')
  990. return
  991. }
  992. //获取数组
  993. let arr = []
  994. if (index === 99) {
  995. //重置函数
  996. arr = selectEleFormula.value
  997. } else if (index === 3) {
  998. //参数1
  999. arr = selectEleFormula3.value
  1000. } else if (index === 4) {
  1001. //参数2
  1002. arr = selectEleFormula4.value
  1003. }
  1004. const map = formulaMenuMap.value
  1005. if (arr.length <= 0) {
  1006. window?.$message.warning('公式开头不能是运算符号')
  1007. return
  1008. }
  1009. let { type, name } = getObjValue(arr[arr.length - 1])
  1010. if (type === 'Operator') {
  1011. window?.$message.warning('运算符号无法连续出现在运算符号后面')
  1012. return
  1013. }
  1014. if (type === 'Brackets' && name === '(') {
  1015. window?.$message.warning('运算符号无法连续出现在左括号后面')
  1016. return
  1017. }
  1018. const obj = getObjValue(map[val])
  1019. //公共对象
  1020. const data = {
  1021. type: 'Operator',
  1022. name: symbolReg.exec(obj.name)[1],
  1023. selected: false,
  1024. template: obj.template,
  1025. index: getRandom(5),
  1026. }
  1027. if (index === 99) {
  1028. selectEleFormula.value.push(data)
  1029. } else if (index === 3) {
  1030. selectEleFormula3.value.push(data)
  1031. } else if (index === 4) {
  1032. selectEleFormula4.value.push(data)
  1033. }
  1034. }
  1035. //删除
  1036. const resetFunDel = () => {
  1037. const index = curRangeFocusIndex.value
  1038. if (index <= 0) {
  1039. window?.$message.warning('非正常操作')
  1040. return
  1041. }
  1042. //获取数组
  1043. let arr = []
  1044. if (index === 99) {
  1045. //重置函数
  1046. arr = selectEleFormula.value
  1047. } else if (index === 3) {
  1048. //参数1
  1049. arr = selectEleFormula3.value
  1050. } else if (index === 4) {
  1051. //参数2
  1052. arr = selectEleFormula4.value
  1053. }
  1054. const newArr = deepClone(arr)
  1055. if (newArr.length <= 0) {
  1056. window?.$message.warning('请先添加相关元素')
  1057. return
  1058. }
  1059. const indexs = arrIndex(newArr, 'selected', true)
  1060. if (indexs !== -1) {
  1061. newArr.splice(indexs, 1)
  1062. if (index === 99) {
  1063. selectEleFormula.value = newArr
  1064. } else if (index === 3) {
  1065. selectEleFormula3.value = newArr
  1066. } else if (index === 4) {
  1067. selectEleFormula4.value = newArr
  1068. }
  1069. } else {
  1070. newArr.splice(newArr.length - 1, 1)
  1071. if (index === 99) {
  1072. selectEleFormula.value = newArr
  1073. } else if (index === 3) {
  1074. selectEleFormula3.value = newArr
  1075. } else if (index === 4) {
  1076. selectEleFormula4.value = newArr
  1077. }
  1078. }
  1079. }
  1080. //清空
  1081. const resetFunClear = () => {
  1082. const index = curRangeFocusIndex.value
  1083. if (index <= 0) {
  1084. window?.$message.warning('非正常操作')
  1085. return
  1086. }
  1087. if (index === 99) {
  1088. //重置函数
  1089. selectEleFormula.value = []
  1090. } else if (index === 3) {
  1091. //参数1
  1092. selectEleFormula3.value = []
  1093. } else if (index === 4) {
  1094. //参数2
  1095. selectEleFormula4.value = []
  1096. }
  1097. }
  1098. //被点击
  1099. const selectEleFormulaItem = (item) => {
  1100. const index = curRangeFocusIndex.value
  1101. if (index <= 0) {
  1102. window?.$message.warning('非正常操作')
  1103. return
  1104. }
  1105. //获取数组
  1106. let arr = []
  1107. if (index === 99) {
  1108. //重置函数
  1109. arr = selectEleFormula.value
  1110. } else if (index === 3) {
  1111. //参数1
  1112. arr = selectEleFormula3.value
  1113. } else if (index === 4) {
  1114. //参数2
  1115. arr = selectEleFormula4.value
  1116. }
  1117. for (let i = 0; i < arr.length; i++) {
  1118. if (item.index === arr[i].index) {
  1119. arr[i].selected = !arr[i].selected
  1120. } else {
  1121. arr[i].selected = false
  1122. }
  1123. }
  1124. if (index === 99) {
  1125. selectEleFormula.value = arr
  1126. } else if (index === 3) {
  1127. selectEleFormula3.value = arr
  1128. } else if (index === 4) {
  1129. selectEleFormula4.value = arr
  1130. }
  1131. }
  1132. //赋值给等号右边的数组
  1133. const processFormula = ref([])
  1134. const setProcessFormula = () => {
  1135. const arr = selectEleFormula.value
  1136. let leftNum = 0, rightNum = 0
  1137. arr.forEach(({ type, name }) => {
  1138. if (type === 'Brackets') {
  1139. if (name === '(') {
  1140. leftNum++
  1141. } else if (name === ')') {
  1142. rightNum++
  1143. }
  1144. }
  1145. })
  1146. if (leftNum !== rightNum) {
  1147. window?.$message.warning('左右括号数量不相等,请先检查是否正确')
  1148. return
  1149. }
  1150. processFormula.value = deepClone(arr)
  1151. isResetFun.value = false
  1152. isScrollBar.value = true
  1153. }
  1154. //获取项目数据
  1155. const projectId = ref('')
  1156. const projectList = ref([])
  1157. const getProjectDataApi = async () => {
  1158. const { data } = await projectApi.page({
  1159. current: 1,
  1160. size: 99999,
  1161. })
  1162. projectList.value = getArrValue(data?.records)
  1163. }
  1164. //项目被选择
  1165. const contractId = ref('')
  1166. const contractList = ref([])
  1167. const projectChange = async () => {
  1168. contractId.value = ''
  1169. const { data } = await contractApi.getList(projectId.value)
  1170. contractList.value = getArrValue(data)
  1171. }
  1172. //项目查询
  1173. const projectQueryClick = () => {
  1174. console.log('原来就没做这个功能')
  1175. }
  1176. //允许偏差值范围
  1177. const deviationRangeSymbol = ref('【min,max】')
  1178. //模式切换
  1179. const deviationRangeResult = ref('1')
  1180. const deviationRangeResultChange = () => {
  1181. if (deviationRangeResult.value === '1') {
  1182. if (!['<', '≤'].includes(deviationRangeSymbol.value)) {
  1183. curRangeFocusIndex.value = 1
  1184. } else if (!['>', '≥'].includes(deviationRangeSymbol.value)) {
  1185. curRangeFocusIndex.value = 2
  1186. }
  1187. } else if (deviationRangeResult.value === '2') {
  1188. if (!['<', '≤'].includes(deviationRangeSymbol.value)) {
  1189. curRangeFocusIndex.value = 3
  1190. } else if (!['>', '≥'].includes(deviationRangeSymbol.value)) {
  1191. curRangeFocusIndex.value = 4
  1192. }
  1193. }
  1194. }
  1195. //允许偏差值范围1
  1196. const deviationRangeTag1 = ref('')
  1197. const deviationRangeTags1 = ref([])
  1198. const deviationRangeBlur1 = () => {
  1199. if (deviationRangeTag1.value) {
  1200. if (deviationRangeTag1.value && deviationRangeTags1.value[0]) {
  1201. emit('uncheck', deviationRangeTags1.value[0].id)
  1202. }
  1203. deviationRangeTags1.value = []
  1204. }
  1205. }
  1206. //允许偏差值范围2
  1207. const deviationRangeTag2 = ref('')
  1208. const deviationRangeTags2 = ref([])
  1209. const deviationRangeBlur2 = () => {
  1210. if (deviationRangeTag2.value) {
  1211. if (deviationRangeTag2.value && deviationRangeTags2.value[0]) {
  1212. emit('uncheck', deviationRangeTags2.value[0].id)
  1213. }
  1214. deviationRangeTags2.value = []
  1215. }
  1216. }
  1217. //当前在哪个输入框
  1218. const curRangeFocusIndex = ref(0)
  1219. const rangeAddingTag = () => {
  1220. console.log('原来的版本就啥也没做')
  1221. }
  1222. //选择参数
  1223. const isRangeSelectEle = ref(false)
  1224. const deviationRangeSelectEle = () => {
  1225. const val = !isRangeSelectEle.value
  1226. isRangeSelectEle.value = val
  1227. isScrollBar.value = !val
  1228. }
  1229. //手写模式
  1230. const handWritText = ref('')
  1231. const handWritEleMap = ref({})
  1232. const isHandWritEle = ref(false)
  1233. const handWritClick = () => {
  1234. try {
  1235. let { text, eleMap } = formulaArrayToString(processFormula.value, resultFormula.value)
  1236. handWritText.value = text
  1237. handWritEleMap.value = JSON.stringify(eleMap)
  1238. isHandWritEle.value = true
  1239. } catch (error) {
  1240. console.log(error)
  1241. window?.$message.error('生成公式文本失败')
  1242. }
  1243. }
  1244. //手写模式转换
  1245. const handWritTransform = () => {
  1246. try {
  1247. let formula = formulaStringToArray(handWritText.value, handWritEleMap.value, formulaMenuMap.value)
  1248. processFormula.value = getArrValue(formula.processFormula)
  1249. const results = resultFormula.value
  1250. formula.resultFormula[0].id = results[0].id
  1251. formula.resultFormula[0].name = results[0].name
  1252. formula.resultFormula[0].tableElementKey = results[0].tableElementKey
  1253. resultFormula.value[0].children = formula.resultFormula[0].children
  1254. handWritEleClose()
  1255. } catch (error) {
  1256. console.log(error)
  1257. window?.$message.error('转成配置用的数组失败')
  1258. }
  1259. }
  1260. //手写模式关闭
  1261. const handWritEleClose = () => {
  1262. isHandWritEle.value = false
  1263. handWritText.value = ''
  1264. handWritEleMap.value = {}
  1265. }
  1266. const findNumber = (array) => {
  1267. for (const item of array) {
  1268. if (!item.children) continue
  1269. const child = item.children.find(child => child.number)
  1270. if (child) return child.number
  1271. }
  1272. return ''
  1273. }
  1274. //获取元素
  1275. const getTemplateFt = (item) => {
  1276. let template = item?.template?.ft
  1277. item.template.args.forEach(obj => {
  1278. template = template.replace(obj.key, obj.m)
  1279. })
  1280. //item.arguments[0].tableElementKey = item.arguments[0].tableElementKey.replace('_key', ':key')
  1281. return template
  1282. }
  1283. //输入文本
  1284. const enterTextClick = (item, indexs) => {
  1285. item.arguments[indexs] = ''
  1286. }
  1287. //选择元素
  1288. const elementsArgumenItem = ref({})
  1289. const selectingElements = (item, indexs) => {
  1290. elementsArgumenItem.value = {
  1291. arguments: item.arguments,
  1292. index: indexs,
  1293. }
  1294. }
  1295. //当前元素
  1296. const setCurElement = (item, index, indexs) => {
  1297. let tmp = deepClone(equationSelectEle.value)
  1298. tmp['tableElementKey'] = tmp['tableElementKey'].replace('_key', ':key')
  1299. item.arguments[indexs] = tmp.children[index].arguments[indexs]
  1300. }
  1301. //保存
  1302. const submitLoading = ref(false)
  1303. const submitClick = async () => {
  1304. if (isResetFun.value) {
  1305. //重置函数
  1306. setProcessFormula()
  1307. } else {
  1308. //允许偏差值范围
  1309. submitLoading.value = true
  1310. const result = deviationRangeResult.value
  1311. deviationRangeObj.value = {
  1312. symbol: deviationRangeSymbol.value,
  1313. model: result,
  1314. arguments1: result === '2' ? selectEleFormula3.value : deviationRangeTag1.value,
  1315. arguments2: result === '2' ? selectEleFormula4.value : deviationRangeTag2.value,
  1316. }
  1317. //处理数据
  1318. const process = processFormula.value, results = resultFormula.value
  1319. let obj = formulaArrayToString(process, results)
  1320. let deviationRangeText = rangeToString(deviationRangeObj.value, obj.eleMap)
  1321. obj.eleMap.deviationRangeJson = JSON.stringify(deviationRangeObj.value)
  1322. //特殊公式会有number
  1323. let number = findNumber(process) || findNumber(results)
  1324. //发起请求
  1325. const { eleId, globalType, nodeId, pid } = getObjValue(dataInfo.value)
  1326. const formData = {
  1327. formula: obj.text,
  1328. remark: '',
  1329. nodeId: nodeId,
  1330. elementId: eleId,
  1331. scale: isRetain.value ? retainNum.value : '',
  1332. number: number,
  1333. map: JSON.stringify(obj.eleMap),
  1334. scope: globalType,
  1335. projectId: projectId.value || pid,
  1336. dev: deviationRangeText,
  1337. }
  1338. let res = {}
  1339. if (isNullES(formulaId.value)) {
  1340. //新增
  1341. res = await formulaApi.save({ ...formData, ver:1 })
  1342. } else {
  1343. //更新
  1344. res = await formulaApi.update({ id: formulaId.value, ...formData })
  1345. }
  1346. const { code, msg, data } = getObjValue(res)
  1347. if (code !== 200) {
  1348. submitLoading.value = false
  1349. return
  1350. }
  1351. let msgStr = '保存成功'
  1352. if (msg === '公式已删除') {
  1353. formulaId.value = ''
  1354. msgStr = msg
  1355. } else if (!isNullES(data)) {
  1356. formulaId.value = data
  1357. }
  1358. window?.$message.success(msgStr)
  1359. getFormulaStringToArrayApi()
  1360. submitLoading.value = false
  1361. }
  1362. }
  1363. //关闭抽屉
  1364. const drawerClose = () => {
  1365. if (isResetFun.value) {
  1366. //重置函数
  1367. isResetFun.value = false
  1368. isScrollBar.value = true
  1369. curRangeFocusIndex.value = 0
  1370. } else if (deviationRangeShow.value) {
  1371. //允许偏差值范围
  1372. deviationRangeShow.value = false
  1373. isRangeSelectEle.value = false
  1374. curRangeFocusIndex.value = 0
  1375. } else {
  1376. isShow.value = false
  1377. //重置元素
  1378. isResetFun.value = false
  1379. isScrollBar.value = true
  1380. //允许偏差值范围
  1381. deviationRangeShow.value = false
  1382. curRangeFocusIndex.value = 0
  1383. //选择的元素
  1384. selectEleFormula.value = []
  1385. selectEleFormula3.value = []
  1386. selectEleFormula4.value = []
  1387. //手写模式
  1388. isHandWritEle.value = false
  1389. handWritText.value = ''
  1390. handWritEleMap.value = {}
  1391. emit('close')
  1392. }
  1393. }
  1394. </script>
  1395. <style lang="scss">
  1396. @import '~src/styles/view/project/edit-formula';
  1397. </style>