conditionAssistance.vue 20 KB

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