experimentationProcess.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  1. <template>
  2. <div class="ele-body">
  3. <el-button type="primary" @click="addHtml('customText')" v-if="edit"
  4. >插入自定义文本</el-button
  5. >
  6. <el-button type="primary" @click="addHtml('customTable')" v-if="edit"
  7. >插入表格</el-button
  8. >
  9. <!-- <el-button type="primary" @click="save()">保存</el-button> -->
  10. <div
  11. style="
  12. display: flex;
  13. width: 100%;
  14. padding: 10px;
  15. border: solid 1px #f1f1f1;
  16. margin-top: 10px;
  17. "
  18. >
  19. <vue-draggable
  20. v-model="list"
  21. group="project1"
  22. :animation="300"
  23. handle=".sort-handle"
  24. style="flex: 1"
  25. >
  26. <div
  27. class="demo-drag-list-item ele-cell"
  28. v-for="item in list"
  29. :key="item.id"
  30. >
  31. <div class="listItem">
  32. <i
  33. class="sort-handle el-icon-_nav move"
  34. style="display: none"
  35. v-if="edit"
  36. ></i>
  37. <i
  38. class="sort-handle el-icon-delete delete"
  39. v-if="edit"
  40. style="display: none"
  41. @click="del(item.id)"
  42. ></i>
  43. <customText
  44. :ref="'customTextRef' + item.id"
  45. style="flex: 1"
  46. v-if="item.type == 'customText'"
  47. :id="item.id"
  48. :form="item.value"
  49. :valueObj="item.valueObj"
  50. @editShow="editShowFn"
  51. @calculation="calculation"
  52. :edit="edit"
  53. ></customText>
  54. <customTable
  55. :ref="'customTextRef' + item.id"
  56. style="flex: 1"
  57. v-if="item.type == 'customTable'"
  58. :id="item.id"
  59. :form="item.value"
  60. :valueObj="item.valueObj"
  61. @calculation="calculation"
  62. @editShow="editShowFn"
  63. :edit="edit"
  64. ></customTable>
  65. </div>
  66. </div>
  67. </vue-draggable>
  68. <el-card class="box-card" v-show="editShow" style="width: 320px">
  69. <div slot="header" class="clearfix">
  70. <span>配置</span>
  71. <el-button
  72. style="float: right; padding: 3px 0"
  73. type="text"
  74. @click="editShow = false"
  75. >关闭</el-button
  76. >
  77. </div>
  78. <el-form label-width="80px">
  79. <el-form-item label="字段标识:" prop="id">
  80. <el-input
  81. v-model="domObj.id"
  82. placeholder=""
  83. @change="editInputChange"
  84. ></el-input>
  85. </el-form-item>
  86. <el-form-item label="宽度:" prop="width" v-if="!domObj.isNoWidth">
  87. <el-input
  88. v-model="domObj.width"
  89. type="number"
  90. placeholder=""
  91. @change="editInputChange"
  92. ></el-input>
  93. </el-form-item>
  94. <el-form-item label="是否只读:" prop="readonly">
  95. <el-select
  96. v-model="domObj.readonly"
  97. placeholder="请选择"
  98. @change="editInputChange"
  99. >
  100. <el-option :key="1" label="否" :value="1"> </el-option>
  101. <el-option :key="2" label="是" :value="2"> </el-option>
  102. </el-select>
  103. </el-form-item>
  104. <el-form-item label="计算公式:" prop="readonly">
  105. <el-input
  106. :value="domObj.equation?.map((item) => item.value).join('')"
  107. type="textarea"
  108. placeholder=""
  109. disabled
  110. ></el-input>
  111. <el-button type="primary" @click="setEquation">配置公式</el-button>
  112. <el-button type="primary" @click="delEquation">重置</el-button>
  113. </el-form-item>
  114. </el-form>
  115. </el-card>
  116. </div>
  117. <ele-modal
  118. title="配置公式"
  119. :visible.sync="visible"
  120. :close-on-click-modal="false"
  121. append-to-body
  122. width="800px"
  123. resizable
  124. maxable
  125. >
  126. <div class="formula-builder__selects">
  127. <!-- 选择参数:从已填的非计算参数内容里取 -->
  128. <el-select
  129. v-model="equationUnit.paramSelect"
  130. placeholder="选择参数"
  131. size="mini"
  132. style="width: 100px; margin-right: 8px; flex-shrink: 0"
  133. @change="paramSelectChange($event, 'id')"
  134. filterable
  135. >
  136. <el-option
  137. v-for="item in idList"
  138. :key="item"
  139. :label="item"
  140. :value="item"
  141. />
  142. </el-select>
  143. <!-- 选择运算符 -->
  144. <el-select
  145. v-model="equationUnit.opSelect"
  146. placeholder="选择符号"
  147. size="mini"
  148. style="width: 100px; flex-shrink: 0; margin-right: 8px"
  149. @change="paramSelectChange($event, 'symbol')"
  150. >
  151. <el-option
  152. v-for="op in opSelectOptions"
  153. :key="op"
  154. :label="op"
  155. :value="op"
  156. />
  157. </el-select>
  158. <!-- 选择值 -->
  159. <el-input
  160. v-model="equationUnit.currentValue"
  161. placeholder="输入值"
  162. size="mini"
  163. style="width: 150px; flex-shrink: 0"
  164. >
  165. <template slot="append">
  166. <span
  167. style="cursor: pointer"
  168. @click="paramSelectChange(equationUnit.currentValue, 'value')"
  169. >确认</span
  170. >
  171. </template>
  172. </el-input>
  173. <!-- 替换或者追加 -->
  174. <el-select
  175. v-if="equationUnit.activeIndex != undefined"
  176. v-model="equationUnit.replaceOrAppend"
  177. placeholder="选择"
  178. size="mini"
  179. style="width: 80px; margin-left: 8px; flex-shrink: 0"
  180. >
  181. <el-option key="append" label="追加" value="append" />
  182. <el-option key="replace" label="替换" value="replace" />
  183. </el-select>
  184. <el-input
  185. v-model.number="domObj.units.decimalPlace"
  186. placeholder="小数位"
  187. size="mini"
  188. style="width: 120px; margin-left: 8px; flex-shrink: 0"
  189. >
  190. </el-input>
  191. <el-select
  192. v-model="domObj.units.takeValueMethod"
  193. placeholder="取值方法"
  194. size="mini"
  195. style="width: 100px; margin-left: 8px; flex-shrink: 0"
  196. >
  197. <el-option key="1" label="四舍五入" value="1" />
  198. <el-option key="2" label="去尾" value="2" />
  199. </el-select>
  200. </div>
  201. <!-- 已组装公式标签展示 -->
  202. <div
  203. v-if="equationUnit.equation.length"
  204. style="
  205. display: inline-flex;
  206. flex-wrap: wrap;
  207. max-width: 100%;
  208. margin-top: 5px;
  209. "
  210. >
  211. <el-tag
  212. v-for="(p, index) in equationUnit.equation"
  213. :key="index"
  214. size="mini"
  215. closable
  216. :type="equationUnit.activeIndex === index ? 'primary' : 'info'"
  217. @click="formulaPartsTagClick(index)"
  218. @close="tagItemDelete(index)"
  219. >
  220. {{ p.value }}
  221. </el-tag>
  222. </div>
  223. <el-input
  224. style="margin-top: 5px"
  225. :value="equationUnit.equation?.map((item) => item.value).join('')"
  226. type="textarea"
  227. placeholder=""
  228. disabled
  229. ></el-input>
  230. <div slot="footer" class="footer">
  231. <el-button type="primary" @click="editInputChange('equation')"
  232. >确认</el-button
  233. >
  234. <el-button @click="visible = false">返回</el-button>
  235. </div>
  236. </ele-modal>
  237. </div>
  238. </template>
  239. <script>
  240. import customText from './templateDiv/customText.vue';
  241. import customTable from './templateDiv/customTable.vue';
  242. import VueDraggable from 'vuedraggable';
  243. import { generateRandomString } from '@/utils/util';
  244. export default {
  245. components: {
  246. customText,
  247. VueDraggable,
  248. customTable
  249. },
  250. props: {
  251. edit: {
  252. default: true,
  253. type: Boolean
  254. }
  255. },
  256. computed: {},
  257. data() {
  258. return {
  259. list: [],
  260. editShow: false,
  261. visible: false,
  262. templateDivRef: '',
  263. domObj: { units: {} },
  264. idList: [],
  265. opSelectOptions: ['+', '-', '*', '/', '%', '(', ')'],
  266. equationUnit: {
  267. equation: [],
  268. activeIndex: '',
  269. paramSelect: '',
  270. opSelect: '',
  271. currentValue: '',
  272. replaceOrAppend: 'append'
  273. }
  274. };
  275. },
  276. mounted() {},
  277. created() {},
  278. methods: {
  279. // 计算
  280. calculation() {
  281. this.getValue();
  282. let equation = [];
  283. this.list.forEach((item) => {
  284. equation.push({
  285. id: item.id,
  286. equation: item.equation
  287. });
  288. });
  289. equation.forEach((item) => {
  290. for (const key in item.equation) {
  291. let { data, units } = this.getObjValue(); //每次计算都获取最新的值
  292. let value = '';
  293. if (item.equation[key].length) {
  294. item.equation[key].forEach((equationItem) => {
  295. if (
  296. equationItem.type == 'symbol' ||
  297. equationItem.type == 'value'
  298. ) {
  299. value += equationItem.value;
  300. } else if (equationItem.type == 'id') {
  301. value += Number(data[equationItem.value]) || 0;
  302. }
  303. });
  304. if (units[key]?.decimalPlace) {
  305. if (units[key]?.takeValueMethod) {
  306. value =
  307. units[key]?.takeValueMethod == 1
  308. ? parseFloat(eval(value).toFixed(units[key].decimalPlace))
  309. : this.truncateToFixedManual(
  310. eval(value),
  311. units[key].decimalPlace
  312. );
  313. } else {
  314. value = parseFloat(
  315. eval(value).toFixed(units[key].decimalPlace)
  316. );
  317. }
  318. } else {
  319. value = parseFloat(eval(value).toFixed(2));
  320. }
  321. if (this.$refs['customTextRef' + item.id][0]) {
  322. this.$refs['customTextRef' + item.id][0].equationValue({
  323. domId: key,
  324. value
  325. });
  326. }
  327. }
  328. }
  329. });
  330. },
  331. truncateToFixedManual(num, decimalPlaces) {
  332. let factor = Math.pow(10, decimalPlaces);
  333. return Math.floor(num * factor) / factor;
  334. },
  335. getObjValue() {
  336. this.getValue();
  337. let data = {};
  338. let units = {};
  339. this.list.forEach((item) => {
  340. units = { ...item.units, ...units };
  341. if (item.type == 'customText') {
  342. data = { ...item.valueObj, ...data };
  343. } else {
  344. item.valueObj.columns.forEach((row) => {
  345. row.forEach((cell) => {
  346. data[cell.id] = cell.value;
  347. });
  348. });
  349. }
  350. });
  351. return { data: data || {}, units: units || {} };
  352. },
  353. setEquation() {
  354. this.getValue();
  355. this.idList = [];
  356. if (this.domObj.equation) {
  357. this.equationUnit.equation = JSON.parse(
  358. JSON.stringify(this.domObj.equation)
  359. );
  360. this.equationUnit.activeIndex = this.domObj.equation.length;
  361. } else {
  362. this.equationUnit.equation = [];
  363. }
  364. this.list.forEach((item) => {
  365. if (item.type == 'customText') {
  366. for (let key in item.valueObj) {
  367. this.idList.push(key);
  368. }
  369. } else {
  370. item.valueObj.columns.forEach((row) => {
  371. row.forEach((cell) => {
  372. this.idList.push(cell.id);
  373. });
  374. });
  375. }
  376. });
  377. this.visible = true;
  378. },
  379. delEquation() {
  380. this.equationUnit.equation = [];
  381. this.editInputChange('equation');
  382. },
  383. tagItemDelete(index) {
  384. this.equationUnit.equation.splice(index, 1);
  385. },
  386. formulaPartsTagClick(index, row) {
  387. if (!this.equationUnit.replaceOrAppend) {
  388. // 默认追加
  389. this.equationUnit_replaceOrAppend = 'append';
  390. }
  391. if (
  392. this.equationUnit.activeIndex &&
  393. this.equationUnit.activeIndex === index
  394. ) {
  395. this.$set(this.equationUnit, 'activeIndex', undefined);
  396. } else {
  397. this.$set(this.equationUnit, 'activeIndex', index);
  398. }
  399. },
  400. paramSelectChange(val, type) {
  401. if (!val) {
  402. return;
  403. }
  404. if (type == 'id') {
  405. this.setValue({ type: 'id', value: val });
  406. this.equationUnit.paramSelect = null;
  407. } else if (type == 'symbol') {
  408. this.setValue({ type: 'symbol', value: val });
  409. this.equationUnit.opSelect = null;
  410. } else if (type == 'value') {
  411. this.setValue({ type: 'value', value: val });
  412. }
  413. },
  414. setValue(val) {
  415. if (this.equationUnit.activeIndex != undefined) {
  416. if (
  417. !this.equationUnit.replaceOrAppend ||
  418. this.equationUnit.replaceOrAppend === 'replace'
  419. ) {
  420. this.equationUnit.equation.splice(
  421. this.equationUnit.activeIndex,
  422. 1,
  423. val
  424. );
  425. } else if (this.equationUnit.replaceOrAppend === 'append') {
  426. this.equationUnit.equation.splice(
  427. this.equationUnit.activeIndex + 1,
  428. 0,
  429. val
  430. );
  431. // 追加后activeIndex后移一位
  432. this.$set(
  433. this.equationUnit,
  434. 'activeIndex',
  435. this.equationUnit.activeIndex + 1
  436. );
  437. }
  438. } else {
  439. this.equationUnit.equation.push(val);
  440. }
  441. },
  442. init(list) {
  443. this.list = JSON.parse(list);
  444. if (this.list.length) {
  445. this.$nextTick(() => {
  446. this.list.forEach((item) => {
  447. this.$refs['customTextRef' + item.id][0].init({
  448. form: item.value,
  449. valueObj: item.valueObj,
  450. equation: item.equation,
  451. units: item.units
  452. });
  453. });
  454. });
  455. }
  456. },
  457. editShowFn({ templateDivRef, domObj }) {
  458. this.templateDivRef = templateDivRef;
  459. this.$set(this, 'domObj', domObj);
  460. this.editShow = true;
  461. },
  462. editInputChange(type) {
  463. if (type == 'equation') {
  464. this.visible = false;
  465. this.domObj.equation = JSON.parse(
  466. JSON.stringify(this.equationUnit.equation)
  467. );
  468. }
  469. this.$nextTick(() => {
  470. this.$refs[this.templateDivRef][0].editInputChange(this.domObj);
  471. });
  472. },
  473. del(id) {
  474. this.list = this.list.filter((item) => item.id != id);
  475. },
  476. addHtml(type) {
  477. this.list.push({
  478. id: generateRandomString(6),
  479. type: type,
  480. value: '',
  481. valueObj: {}
  482. });
  483. },
  484. getValue() {
  485. this.list.forEach((item, index) => {
  486. let { form, valueObj, equation, units } =
  487. this.$refs['customTextRef' + item.id][0].getValue();
  488. this.$set(this.list[index], 'value', form);
  489. this.$set(this.list[index], 'valueObj', valueObj);
  490. this.$set(this.list[index], 'equation', equation);
  491. this.$set(this.list[index], 'units', units);
  492. });
  493. return this.list;
  494. }
  495. }
  496. };
  497. </script>
  498. <style scoped lang="scss">
  499. .listItem {
  500. padding: 5px;
  501. padding-top: 15px;
  502. border: solid 1px #f1f1f1;
  503. display: flex;
  504. width: 100%;
  505. align-items: center;
  506. margin-top: 3px;
  507. position: relative;
  508. }
  509. .sort-handle {
  510. font-size: 16px;
  511. position: absolute;
  512. left: 0;
  513. top: 0;
  514. }
  515. .move {
  516. cursor: move;
  517. }
  518. .delete {
  519. cursor: pointer;
  520. left: 20px;
  521. color: #f56c6c;
  522. }
  523. .listItem:hover {
  524. .sort-handle {
  525. display: block !important;
  526. }
  527. }
  528. </style>