conditionAssistance.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725
  1. <template>
  2. <BasicModal
  3. @register="register"
  4. title="风机运行工况辅助决策"
  5. :maskStyle="{ backgroundColor: '#000000aa' }"
  6. width="1200px"
  7. v-bind="$attrs"
  8. @ok="onSubmit"
  9. @cancel="onSubmit"
  10. :canFullscreen="false"
  11. :destroyOnClose="true"
  12. :footer="null"
  13. >
  14. <div class="modal-box">
  15. <div class="right-box">
  16. <!-- <div class="box-title">风机信息</div> -->
  17. <dv-decoration7 style="height: 20px">
  18. <div class="box-title">风机信息</div>
  19. </dv-decoration7>
  20. <div class="info-container">
  21. <template v-if="isMock">
  22. <div v-for="(item, index) in fanInfo" class="info-item" :key="index">
  23. <div class="title">{{ item.title }}:</div>
  24. <div class="value">{{ fanInfoData && fanInfoData[item.code] ? fanInfoData[item.code] : '-' }}</div>
  25. </div>
  26. </template>
  27. <template v-else>
  28. <div v-for="(item, index) in columns" class="info-item" :key="index">
  29. <div class="title">{{ item['title'] }}:</div>
  30. <div v-if="item['dict']" class="value">{{ render.renderDictText(selectData[item['dataIndex']], 'adjustmentMethod') }}</div>
  31. <div v-else class="value">{{ selectData && selectData[item['dataIndex']] ? selectData[item['dataIndex']] : '-' }}</div>
  32. </div>
  33. </template>
  34. </div>
  35. </div>
  36. <div class="center-box">
  37. <a-spin :spinning="loadding" tip="正在计算,请稍等。。。">
  38. <div ref="chartRef" class="info-echarts" style="width: 450px; height: 375px"></div>
  39. <div v-if="resultObj" class="result-tip">
  40. 最佳工况点为
  41. <span style="color: #9a60b4; padding: 0 10px; font-weight: 600">{{ parseInt(resultObj.Hz) + (showFre ? 'Hz' : '°') }}</span>
  42. <span style="color: #c60000; padding: 0 10px; font-weight: 600">{{ formatNum(resultObj.x) }} m³/s</span>
  43. <span style="color: #c60000; padding: 0 10px; font-weight: 600">{{ formatNum(resultObj.y) }} Pa</span></div
  44. >
  45. </a-spin>
  46. </div>
  47. <div class="left-box">
  48. <!-- <div class="box-title">曲线方程</div> -->
  49. <dv-decoration7 style="height: 20px">
  50. <div class="box-title">曲线方程</div>
  51. </dv-decoration7>
  52. <div class="info-lines">
  53. <div v-for="(item, index) in lineEquation" class="info-item" :key="index">
  54. <div class="title">{{ item }}</div>
  55. </div>
  56. </div>
  57. </div>
  58. </div>
  59. <div class="setting-box">
  60. <!-- <div class="left-buttons"> -->
  61. <!-- <div class="btn btn1" @click="edit('info')">编辑风机信息</div> -->
  62. <!-- <div class="btn btn1" @click="edit('line')">编辑特性曲线</div> -->
  63. <!-- 风机当前角度:<span>{{ selectData.bladeAngle }} &nbsp;°</span> -->
  64. <!-- </div> -->
  65. <!-- <div class="border-clip"></div> -->
  66. <div class="right-inputs">
  67. <div class="vent-flex-row">
  68. <div class="input-title">风量(m³/s):</div>
  69. <Input class="input-box" size="large" v-model:value="uQ" />
  70. <div class="input-title">风压(Pa):</div>
  71. <Input class="input-box" size="large" v-model:value="uH" />
  72. </div>
  73. <div class="btn btn1" @click="makeLine">决策工况</div>
  74. </div>
  75. </div>
  76. <!-- <div v-if="formShow" class="is-close" :class="{ 'is-open': formShow }">
  77. <a-divider orientation="left" style="border-color: #00d8ff22">{{ formType }}</a-divider>
  78. <BasicForm @register="registerForm" @submit="handleSubmit" :schemas="columns" />
  79. </div> -->
  80. </BasicModal>
  81. </template>
  82. <script lang="ts" setup>
  83. //ts语法
  84. import { ref, onMounted, reactive, nextTick, defineProps, defineEmits, watch } from 'vue';
  85. import echarts from '/@/utils/lib/echarts';
  86. import { setOption, initData, fanInfoData, fanInfo, getSchamas, getSchamas1, lineFormData } from '../main.data.ts';
  87. import { BasicModal, useModalInner } from '/@/components/Modal';
  88. import { BasicForm, useForm } from '/@/components/Form/index';
  89. import { Input } from 'ant-design-vue';
  90. import { Decoration7 as DvDecoration7 } from '@kjgl77/datav-vue3';
  91. import { message } from 'ant-design-vue';
  92. import { formatNum } from '/@/utils/ventutil';
  93. import { getTableHeaderColumns } from '/@/hooks/web/useWebColumns';
  94. import { useGlobSetting } from '/@/hooks/setting';
  95. import { render } from '/@/utils/common/renderUtils';
  96. const { sysOrgCode } = useGlobSetting();
  97. const props = defineProps({
  98. deviceType: {
  99. type: String,
  100. },
  101. selectData: {
  102. type: Object,
  103. default: () => {},
  104. },
  105. m3: {
  106. type: Number,
  107. default: 670.8,
  108. },
  109. });
  110. const emit = defineEmits(['close', 'register', 'openModal']);
  111. type AssistanceItemType = {
  112. angle: number;
  113. Hz: number;
  114. a: number;
  115. b: number;
  116. c: number;
  117. min: number;
  118. max: number;
  119. };
  120. const columns = ref([]);
  121. const showFre = ref(true); // 是否显示频率曲线, 是显示,不是显示角度
  122. const isMock = false;
  123. let option = reactive({});
  124. // 注册 modal
  125. const [register, { closeModal }] = useModalInner(() => {
  126. nextTick(() => {
  127. computeAssistance();
  128. option = setOption(props.deviceType);
  129. if (option['xAxis']) option['xAxis']['data'] = xData;
  130. option['series'] = yDataList;
  131. initEcharts();
  132. });
  133. });
  134. const loadding = ref<boolean>(false);
  135. const formShow = ref(false);
  136. const formType = ref('');
  137. const chartRef = ref();
  138. const myChart = ref();
  139. const refresh = ref(true);
  140. const xData: any[] = [];
  141. const yDataList: [] = [];
  142. let lineNum = 0;
  143. const lineEquation = ref<string[]>([]);
  144. const deviceData = ref({});
  145. const uQ = ref<string | undefined>(undefined); // 100 - 400
  146. const uH = ref<number | undefined>(undefined); // - 1000
  147. const resultObj = ref<{ x: number; y: number; Hz: number } | null>(null);
  148. const [registerForm, {}] = useForm({
  149. labelWidth: 120,
  150. actionColOptions: {
  151. span: 24,
  152. },
  153. compact: true,
  154. showSubmitButton: true,
  155. submitButtonOptions: {
  156. text: '提交',
  157. preIcon: '',
  158. },
  159. showResetButton: true,
  160. resetButtonOptions: {
  161. text: '关闭',
  162. preIcon: '',
  163. },
  164. resetFunc: async () => {
  165. formShow.value = false;
  166. },
  167. });
  168. function computeAssistance() {
  169. const assistanceData = initData(props.deviceType);
  170. lineNum = 0;
  171. const assistanceDataList = [];
  172. const lineEquationList: string[] = [];
  173. for (const key in assistanceData) {
  174. const item = assistanceData[key];
  175. assistanceDataList.push(item);
  176. lineEquationList.push(
  177. `H${parseInt(item['Hz'])} = ${item['a']}Q² ${Number(item['b']) > 0 ? '+' : '-'} ${Math.abs(Number(item['b'])).toFixed(5)}Q ${
  178. Number(item['c']) > 0 ? '+' : '-'
  179. } ${Math.abs(Number(item['c'])).toFixed(5)}`
  180. );
  181. }
  182. lineEquation.value = lineEquationList;
  183. lineNum = assistanceDataList.length;
  184. // const xDataMin =
  185. // Math.min.apply(
  186. // Math,
  187. // assistanceDataList.map((item) => {
  188. // return item.min;
  189. // })
  190. // ) - 10;
  191. let xDataMin = Math.min.apply(
  192. Math,
  193. assistanceDataList.map((item) => {
  194. return item.min;
  195. })
  196. );
  197. let xDataMax = Math.max.apply(
  198. Math,
  199. assistanceDataList.map((item) => {
  200. return item.max;
  201. })
  202. );
  203. xDataMin = Number((xDataMin - (xDataMax - xDataMin) / 10).toFixed(0));
  204. xDataMax = Number((xDataMax + (xDataMax - xDataMin) / 10).toFixed(0));
  205. fanInfoData.flfw = `${xDataMin}~${xDataMax}`;
  206. const computeItem = (item: AssistanceItemType) => {
  207. const min = item.min;
  208. const max = item.max;
  209. const HList: number[] = [];
  210. for (let i = xDataMin; i <= xDataMax; i++) {
  211. if (i < min) {
  212. HList.push(null);
  213. } else if (i > max) {
  214. HList.push(null);
  215. } else {
  216. HList.push(item.a * i * i + item.b * i + item.c);
  217. }
  218. }
  219. return HList;
  220. };
  221. for (const key in assistanceData) {
  222. const element: AssistanceItemType = assistanceData[key];
  223. const yData: number[] = computeItem(element);
  224. const series = {
  225. name: `${element['Hz']}${showFre.value ? 'Hz' : '°'}`,
  226. type: 'line',
  227. smooth: true,
  228. showSymbol: false,
  229. symbol: 'none',
  230. emphasis: {
  231. focus: 'series',
  232. },
  233. itemStyle: { normal: { label: { show: true } } },
  234. lineStyle: {
  235. width: 1,
  236. color: '#ffffff88',
  237. },
  238. zlevel: 0,
  239. z: 1,
  240. endLabel: {
  241. show: true,
  242. formatter: '{a}',
  243. distance: 0,
  244. color: '#39E9FE99',
  245. backgroundColor: 'transparent',
  246. padding: [3, 3, 2, 3],
  247. },
  248. data: yData,
  249. };
  250. yDataList.push(series);
  251. }
  252. for (let i = xDataMin; i <= xDataMax; i++) {
  253. xData.push(i);
  254. }
  255. }
  256. function computeRLine() {
  257. if (uH.value && uQ.value) {
  258. const R = uH.value / Number(uQ.value) / Number(uQ.value);
  259. const yAxis: number[] = [];
  260. for (let i = 0; i < xData.length; i++) {
  261. const x = xData[i];
  262. const y = R * x * x;
  263. if (x == uQ.value) {
  264. uH.value = y;
  265. }
  266. yAxis.push(y);
  267. }
  268. const series = {
  269. name: 'R',
  270. type: 'line',
  271. smooth: true,
  272. showSymbol: false,
  273. zlevel: 0,
  274. emphasis: {
  275. focus: 'series',
  276. },
  277. itemStyle: { normal: { label: { show: true } } },
  278. lineStyle: {
  279. width: 2,
  280. color: '#D0A343',
  281. },
  282. endLabel: {
  283. show: true,
  284. formatter: '{a}',
  285. distance: 0,
  286. color: '#D0A343',
  287. },
  288. data: yAxis,
  289. };
  290. yDataList[lineNum] = series;
  291. }
  292. }
  293. function reSetLine() {
  294. let minIndex = -1;
  295. for (let i = 0; i < yDataList.length; i++) {
  296. if (i !== lineNum && i != lineNum + 1) {
  297. if (yDataList[i]['lineStyle']) yDataList[i]['lineStyle']['color'] = '#ffffff88';
  298. if (yDataList[i]['lineStyle']) yDataList[i]['lineStyle']['width'] = 1;
  299. if (yDataList[i]['endLabel'] && yDataList[i]['endLabel']['color']) {
  300. yDataList[i]['endLabel']['color'] = '#39E9FE99';
  301. }
  302. if (yDataList[i]['endLabel'] && yDataList[i]['endLabel']['backgroundColor']) yDataList[i]['endLabel']['backgroundColor'] = 'transparent';
  303. if (yDataList[i]['z']) yDataList[i]['z'] = 1;
  304. }
  305. if (resultObj.value && `${resultObj.value.Hz}${showFre.value ? 'Hz' : '°'}` == yDataList[i]['name']) {
  306. minIndex = i;
  307. }
  308. }
  309. if (minIndex != -1) {
  310. yDataList[minIndex]['lineStyle']['color'] = '#9A60B4';
  311. yDataList[minIndex]['lineStyle']['width'] = 2;
  312. yDataList[minIndex]['endLabel']['color'] = '#9A60B4';
  313. yDataList[minIndex]['endLabel']['backgroundColor'] = '#111';
  314. yDataList[minIndex]['z'] = 999;
  315. }
  316. }
  317. // 根据风量计算压差
  318. function computePa() {
  319. const R = uH.value / Number(uQ.value) / Number(uQ.value);
  320. const pointX = Number(uQ.value);
  321. const pointY = Number(uH.value);
  322. type ItemType = {
  323. x: number;
  324. y: number;
  325. Hz: number;
  326. };
  327. const assistanceData = initData(props.deviceType);
  328. const paList = new Map<number, ItemType>(); // key 是最近距离
  329. const getIntersectionPoint = (a, b, c, R, min, max) => {
  330. const obj: { x: undefined | number; y: undefined | number } = { x: undefined, y: undefined };
  331. // 计算二次方程的判别式
  332. const discriminant = b * b - 4 * (a - R) * c;
  333. if (discriminant > 0) {
  334. // 有两个实根
  335. const x1 = (-b + Math.sqrt(discriminant)) / (2 * (a - R));
  336. const x2 = (-b - Math.sqrt(discriminant)) / (2 * (a - R));
  337. const y1 = R * x1 * x1;
  338. const y2 = R * x2 * x2;
  339. if (x1 >= min && x1 <= max) {
  340. obj.x = x1;
  341. obj.y = y1;
  342. } else {
  343. obj.x = x2;
  344. obj.y = y2;
  345. }
  346. } else if (discriminant === 0) {
  347. // 有一个实根
  348. const x = -b / (2 * (a - R));
  349. const y = R * x * x;
  350. if (x >= min && x <= max) {
  351. obj.x = x;
  352. obj.y = y;
  353. }
  354. // console.log(`唯一交点: (${x}, ${y})`);
  355. } else {
  356. // 没有实根,交点在虚数域
  357. console.log('没有实数交点');
  358. }
  359. return obj;
  360. };
  361. for (let key in assistanceData) {
  362. const item: AssistanceItemType = assistanceData[key];
  363. paList.set(item.Hz, getIntersectionPoint(item.a, item.b, item.c, R, item.min, item.max));
  364. }
  365. const min = (points: Map<number, ItemType>) => {
  366. const targetX = uQ.value;
  367. const targetY = uH.value;
  368. let minDistance = Number.POSITIVE_INFINITY;
  369. let closestPoint = null;
  370. let keyVal = '';
  371. // 遍历已知点数组,计算距离并更新最小距离和对应的点
  372. for (const [key, point] of points) {
  373. const distance = Math.sqrt((targetX - point.x) ** 2 + (targetY - point.y) ** 2);
  374. if (distance < minDistance) {
  375. minDistance = distance;
  376. closestPoint = point;
  377. keyVal = key;
  378. }
  379. }
  380. if (closestPoint !== null) {
  381. console.log(`距离最小的点是 (${closestPoint.x}, ${closestPoint.y}), 距离为 ${minDistance}`);
  382. resultObj.value = { x: closestPoint.x, y: closestPoint.y, Hz: keyVal };
  383. } else {
  384. console.log('没有找到最小距离的点');
  385. }
  386. };
  387. min(paList);
  388. reSetLine();
  389. }
  390. function computeR() {
  391. if (uQ.value && uH.value) {
  392. computeRLine();
  393. computePa();
  394. if (resultObj.value && resultObj.value.x && resultObj.value.y) {
  395. const series = {
  396. type: 'effectScatter',
  397. symbolSize: 5,
  398. // symbolOffset:[1, 1],
  399. showEffectOn: 'render',
  400. // 涟漪特效相关配置。
  401. rippleEffect: {
  402. // 波纹的绘制方式,可选 'stroke' 和 'fill'。
  403. brushType: 'stroke',
  404. },
  405. zlevel: 1,
  406. z: 999,
  407. itemStyle: {
  408. color: '#C60000',
  409. },
  410. data: [[resultObj.value.x.toFixed(0), Number(resultObj.value.y.toFixed(0))]],
  411. };
  412. yDataList[lineNum + 1] = series;
  413. }
  414. }
  415. }
  416. function edit(flag) {
  417. if (flag == 'info') {
  418. formType.value = '编辑风机信息';
  419. }
  420. if (flag == 'line') {
  421. formType.value = '编辑特性曲线';
  422. }
  423. if (formShow.value == true) {
  424. formShow.value = false;
  425. nextTick(() => {
  426. formShow.value = true;
  427. });
  428. } else {
  429. formShow.value = true;
  430. }
  431. }
  432. async function onSubmit() {
  433. emit('close');
  434. closeModal();
  435. chartRef.value = null;
  436. uQ.value = undefined;
  437. uH.value = undefined;
  438. formType.value = '';
  439. myChart.value = undefined;
  440. refresh.value = true;
  441. xData.length = 0;
  442. yDataList.length = 0;
  443. lineNum = 0;
  444. lineEquation.value = [];
  445. resultObj.value = null;
  446. }
  447. function initEcharts() {
  448. if (chartRef.value) {
  449. computeR();
  450. myChart.value = echarts.init(chartRef.value);
  451. option && myChart.value.setOption(option);
  452. refresh.value = false;
  453. nextTick(() => {
  454. setTimeout(() => {
  455. refresh.value = true;
  456. }, 0);
  457. });
  458. }
  459. }
  460. function makeLine() {
  461. if (uQ.value && uH.value) {
  462. loadding.value = true;
  463. setTimeout(() => {
  464. initEcharts();
  465. loadding.value = false;
  466. }, 1200);
  467. }
  468. }
  469. function handleSubmit() {
  470. message.success('提交成功');
  471. setTimeout(() => {
  472. formShow.value = false;
  473. }, 800);
  474. }
  475. function getColumn() {
  476. let lineColumns = [];
  477. if (props.deviceType) {
  478. lineColumns = getTableHeaderColumns(props.deviceType + '_input') as [];
  479. if (lineColumns && lineColumns.length < 1) {
  480. lineColumns = getTableHeaderColumns(props.deviceType.split('_')[0] + '_input') as [];
  481. }
  482. if (lineColumns.length > 0) {
  483. lineColumns = lineColumns.filter((item) => item['dataIndex'] && (item['dataIndex'] as string).endsWith('_mainFanInfo'));
  484. columns.value = lineColumns;
  485. }
  486. }
  487. if (!columns.value || columns.value.length == 0) {
  488. columns.value = fanInfo;
  489. }
  490. }
  491. watch(
  492. () => props.deviceType,
  493. async () => {
  494. getColumn();
  495. // deviceData.value = await list({ devicetype: 'fanmain', pagetype: 'normal' });
  496. }
  497. );
  498. watch(
  499. () => props.selectData,
  500. async (selectData) => {
  501. deviceData.value = selectData;
  502. if (selectData && selectData['adjustmentMethod_mainFanInfo'] != 'angleadjust') {
  503. // 说明是角度了调节
  504. showFre.value = true;
  505. } else {
  506. showFre.value = false;
  507. }
  508. },
  509. { immediate: true }
  510. );
  511. onMounted(() => {});
  512. </script>
  513. <style scoped lang="less">
  514. .modal-box {
  515. display: flex;
  516. flex-direction: row;
  517. background-color: #ffffff05;
  518. padding: 20px 8px;
  519. border: 1px solid #00d8ff22;
  520. // min-height: 600px;
  521. .box-title {
  522. width: calc(100% - 40px);
  523. text-align: center;
  524. background-color: #1dc1f522;
  525. }
  526. .info-item {
  527. display: flex;
  528. justify-content: space-between;
  529. align-items: center;
  530. padding: 2px 0px;
  531. margin: 4px 0;
  532. background-image: linear-gradient(to right, #39deff15, #3977e500);
  533. &:first-child {
  534. margin-top: 0;
  535. }
  536. .title {
  537. width: 200px;
  538. text-align: left;
  539. padding-left: 20px;
  540. color: #f1f1f1cc;
  541. }
  542. .value {
  543. width: 150px;
  544. color: #00d8ff;
  545. padding-right: 20px;
  546. text-align: right;
  547. }
  548. }
  549. .right-box {
  550. width: 350px;
  551. .info-container {
  552. width: calc(100% - 2px);
  553. margin-top: 5px;
  554. box-shadow: 0px 0px 50px #86baff08 inset;
  555. }
  556. }
  557. .left-box {
  558. width: 350px;
  559. .info-lines {
  560. width: calc(100% - 2px);
  561. height: 390px;
  562. box-shadow: 0px 0px 50px #86baff08 inset;
  563. overflow-y: auto;
  564. margin-top: 5px;
  565. .title {
  566. width: 100%;
  567. color: #f1f1f1cc;
  568. }
  569. }
  570. .info-item {
  571. padding: 8px 0px;
  572. margin: 4px 0;
  573. }
  574. }
  575. .center-box {
  576. margin: 0 10px;
  577. .info-echarts {
  578. // background-color: #ffffff11;
  579. }
  580. .result-tip {
  581. text-align: center;
  582. background-color: #00000011;
  583. line-height: 28px;
  584. margin: 10px 50px 0 50px;
  585. border: 1px solid #00d8ff22;
  586. border-radius: 2px;
  587. }
  588. }
  589. }
  590. .setting-box {
  591. width: 1170px;
  592. height: 70px;
  593. margin: 10px 0;
  594. background-color: #ffffff05;
  595. border: 1px solid #00d8ff22;
  596. display: flex;
  597. align-items: center;
  598. justify-content: center;
  599. .right-inputs {
  600. display: flex;
  601. height: 40px;
  602. margin-right: 10px;
  603. }
  604. .left-buttons {
  605. display: flex;
  606. height: 40px;
  607. margin-left: 15px;
  608. .btn {
  609. margin: 0 10px;
  610. }
  611. span {
  612. color: #00d8ff;
  613. }
  614. }
  615. .border-clip {
  616. width: 1px;
  617. height: 25px;
  618. border-right: 1px solid #8b8b8b77;
  619. }
  620. .input-title {
  621. width: 120px;
  622. }
  623. .input-box {
  624. width: 300px !important;
  625. background: transparent !important;
  626. border-color: #00d8ff44 !important;
  627. margin-right: 20px;
  628. color: #fff !important;
  629. }
  630. .btn {
  631. padding: 8px 20px;
  632. position: relative;
  633. border-radius: 2px;
  634. color: #fff;
  635. width: fit-content;
  636. cursor: pointer;
  637. &::before {
  638. position: absolute;
  639. display: block;
  640. content: '';
  641. width: calc(100% - 4px);
  642. height: calc(100% - 4px);
  643. top: 2px;
  644. left: 2px;
  645. border-radius: 2px;
  646. z-index: -1;
  647. }
  648. }
  649. .btn1 {
  650. border: 1px solid #5cfaff;
  651. &::before {
  652. background-image: linear-gradient(#2effee92, #0cb1d592);
  653. }
  654. &:hover {
  655. border: 1px solid #5cfaffaa;
  656. &::before {
  657. background-image: linear-gradient(#2effee72, #0cb1d572);
  658. }
  659. }
  660. }
  661. }
  662. .is-open {
  663. animation: open 0.5s;
  664. animation-iteration-count: 1;
  665. animation-fill-mode: forwards;
  666. animation-timing-function: ease-in;
  667. }
  668. .is-close {
  669. height: 0px;
  670. }
  671. @keyframes open {
  672. 0% {
  673. height: 0px;
  674. }
  675. 100% {
  676. height: fit-content;
  677. }
  678. }
  679. @keyframes close {
  680. 0% {
  681. height: fit-content;
  682. }
  683. 100% {
  684. height: 0px;
  685. }
  686. }
  687. :deep(.zxm-divider-inner-text) {
  688. color: #cacaca88 !important;
  689. }
  690. :deep(.zxm-form-item) {
  691. margin-bottom: 10px;
  692. }
  693. </style>