edit-formula.vue 59 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464
  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 index = Number(path[1].split('-')[1]) - 1
  554. const item = formulaMenuList.value[path[0]][index]
  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. console.log(equationSelectEleCopy.value)
  565. }
  566. }
  567. //在等式模式下点选计算式
  568. const equationSelectIndex = ref(-1)
  569. const equationSelect = async (path) => {
  570. const selectEle = getObjVal(equationSelectEle.value)
  571. if (!selectEle || !['Element', 'ParamData'].includes(selectEle.type)) {
  572. window?.$message.warning('请先选中元素')
  573. return
  574. }
  575. let obj = {}
  576. try {
  577. const index = Number(path[1].split('-')[1]) - 1
  578. const expression = formulaMenuList.value[path[0]][index]
  579. obj = deepClone(expression)
  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. console.log(tmp)
  1301. //tmp['tableElementKey'] = tmp['tableElementKey'].replace('_key', ':key')
  1302. //item.arguments[indexs] = tmp.children[index].arguments[indexs]
  1303. }
  1304. //保存
  1305. const submitLoading = ref(false)
  1306. const submitClick = async () => {
  1307. if (isResetFun.value) {
  1308. //重置函数
  1309. setProcessFormula()
  1310. } else {
  1311. //允许偏差值范围
  1312. submitLoading.value = true
  1313. const result = deviationRangeResult.value
  1314. deviationRangeObj.value = {
  1315. symbol: deviationRangeSymbol.value,
  1316. model: result,
  1317. arguments1: result === '2' ? selectEleFormula3.value : deviationRangeTag1.value,
  1318. arguments2: result === '2' ? selectEleFormula4.value : deviationRangeTag2.value,
  1319. }
  1320. //处理数据
  1321. const process = processFormula.value, results = resultFormula.value
  1322. let obj = formulaArrayToString(process, results)
  1323. let deviationRangeText = rangeToString(deviationRangeObj.value, obj.eleMap)
  1324. obj.eleMap.deviationRangeJson = JSON.stringify(deviationRangeObj.value)
  1325. //特殊公式会有number
  1326. let number = findNumber(process) || findNumber(results)
  1327. //发起请求
  1328. const { eleId, globalType, nodeId, pid } = getObjValue(dataInfo.value)
  1329. const formData = {
  1330. formula: obj.text,
  1331. remark: '',
  1332. nodeId: nodeId,
  1333. elementId: eleId,
  1334. scale: isRetain.value ? retainNum.value : '',
  1335. number: number,
  1336. map: JSON.stringify(obj.eleMap),
  1337. scope: globalType,
  1338. projectId: projectId.value || pid,
  1339. dev: deviationRangeText,
  1340. }
  1341. let res = {}
  1342. if (isNullES(formulaId.value)) {
  1343. //新增
  1344. res = await formulaApi.save({ ...formData, ver:1 })
  1345. } else {
  1346. //更新
  1347. res = await formulaApi.update({ id: formulaId.value, ...formData })
  1348. }
  1349. const { code, msg, data } = getObjValue(res)
  1350. if (code !== 200) {
  1351. submitLoading.value = false
  1352. return
  1353. }
  1354. let msgStr = '保存成功'
  1355. if (msg === '公式已删除') {
  1356. formulaId.value = ''
  1357. msgStr = msg
  1358. } else if (!isNullES(data)) {
  1359. formulaId.value = data
  1360. }
  1361. window?.$message.success(msgStr)
  1362. getFormulaStringToArrayApi()
  1363. submitLoading.value = false
  1364. }
  1365. }
  1366. //关闭抽屉
  1367. const drawerClose = () => {
  1368. if (isResetFun.value) {
  1369. //重置函数
  1370. isResetFun.value = false
  1371. isScrollBar.value = true
  1372. curRangeFocusIndex.value = 0
  1373. } else if (deviationRangeShow.value) {
  1374. //允许偏差值范围
  1375. deviationRangeShow.value = false
  1376. isRangeSelectEle.value = false
  1377. curRangeFocusIndex.value = 0
  1378. } else {
  1379. isShow.value = false
  1380. //重置元素
  1381. isResetFun.value = false
  1382. isScrollBar.value = true
  1383. //允许偏差值范围
  1384. deviationRangeShow.value = false
  1385. curRangeFocusIndex.value = 0
  1386. //选择的元素
  1387. selectEleFormula.value = []
  1388. selectEleFormula3.value = []
  1389. selectEleFormula4.value = []
  1390. //手写模式
  1391. isHandWritEle.value = false
  1392. handWritText.value = ''
  1393. handWritEleMap.value = {}
  1394. emit('close')
  1395. }
  1396. }
  1397. </script>
  1398. <style lang="scss">
  1399. @import '~src/styles/view/project/edit-formula';
  1400. </style>