action_config.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754
  1. <template>
  2. <el-tabs v-model="topsTab" type="card" class="top_tabs" :disabled="isSortMode">
  3. <el-tab-pane label="执行左脚程序" name="left">
  4. </el-tab-pane>
  5. <el-tab-pane label="执行右脚程序" name="right"></el-tab-pane>
  6. </el-tabs>
  7. <div class="two_tabs">
  8. <div class="item"
  9. :class="item.id === activeTab.id ? 'active' : ''"
  10. v-for="item in tabs" :key="item.id"
  11. @click="toggleTab(item)" v-log="{ describe: { action: '点击切换动作Tab', tabName: item.mode_name, tabId: item.id } }"
  12. :style="{ cursor: isSortMode ? 'not-allowed' : 'pointer', opacity: isSortMode ? 0.5 : 1 }"
  13. >{{item.mode_name}}</div>
  14. </div>
  15. <div class="form-table">
  16. <div v-if="isSortMode" class="sort-tip">
  17. <el-icon><Warning /></el-icon>
  18. <span>排序模式:请拖拽行进行排序,完成后点击"保存排序"</span>
  19. </div>
  20. <div class="btnBox">
  21. <div class="primary-btn" @click="addRow" v-log="{ describe: { action: '点击新增一行' } }" :class="{ disabled: isSortMode }" :style="{ opacity: isSortMode ? 0.5 : 1, cursor: isSortMode ? 'not-allowed' : 'pointer' }">新增一行</div>
  22. <div class="primary-btn" @click="resetConfig" v-log="{ describe: { action: '点击重新初始化', tab: topsTab } }" :class="{ disabled: isSortMode }" :style="{ opacity: isSortMode ? 0.5 : 1, cursor: isSortMode ? 'not-allowed' : 'pointer' }">重新初始化</div>
  23. <div class="primary-btn" @click="reName" v-log="{ describe: { action: '点击重命名配置' } }" :class="{ disabled: isSortMode }" :style="{ opacity: isSortMode ? 0.5 : 1, cursor: isSortMode ? 'not-allowed' : 'pointer' }">重命名配置</div>
  24. <div class="primary-btn" @click="toggleSortMode" v-log="{ describe: { action: isSortMode ? '点击保存排序' : '点击排序' } }">
  25. {{ isSortMode ? '保存排序' : '排序' }}
  26. </div>
  27. <div v-if="isSortMode" class="normal-btn" @click="cancelSort" v-log="{ describe: { action: '点击取消排序' } }">
  28. 取消排序
  29. </div>
  30. <el-radio-group style="margin-left: 10px" v-model="selectID" @click.native.stop="changeSelectId($event,activeTab.id)" :disabled="isSortMode">
  31. <el-radio :label="activeTab.id">切换成执行配置</el-radio>
  32. </el-radio-group>
  33. </div>
  34. <el-table
  35. max-height="700"
  36. :data="tableData"
  37. style="width: 100%"
  38. border
  39. row-key="id"
  40. :row-class-name="getRowClassName"
  41. ref="tableRef"
  42. >
  43. <el-table-column prop="sort" label="排序" width="80" v-if="isSortMode">
  44. <template #default="scope">
  45. <div class="sort-content">
  46. <span class="sort-number">{{ scope.row.sort }}</span>
  47. <div class="sort-handle">
  48. <el-icon><Rank /></el-icon>
  49. </div>
  50. </div>
  51. </template>
  52. </el-table-column>
  53. <el-table-column prop="action_name" label="步骤" >
  54. <template #default="scope">
  55. {{ scope.row.action_name }}
  56. <el-tag type="success" size="small" v-if="calibrationId === scope.row.id">校准位</el-tag>
  57. </template>
  58. </el-table-column>
  59. <el-table-column prop="take_picture" label="是否拍照" width="200px">
  60. <template #default="scope">
  61. <div v-if="!scope.row.is_system">
  62. {{ scope.row.take_picture ? '拍照' : '不拍照' }}
  63. </div>
  64. <span v-else></span>
  65. </template>
  66. </el-table-column>
  67. <el-table-column prop="value" label="操作" >
  68. <template #default="{row, $index}">
  69. <a class="mar-right-10 cursor-pointer" @click="editRow(row, $index)" v-log="{ describe: { action: '点击编辑步骤', id: row.id, action_name: row.action_name } }">编辑</a>
  70. <a class="cursor-pointer" v-if="!row.is_system" @click="deleteRow(row, $index)" v-log="{ describe: { action: '点击删除步骤', id: row.id, action_name: row.action_name } }">删除</a>
  71. </template>
  72. </el-table-column>
  73. </el-table>
  74. </div>
  75. <EditDialog
  76. v-if="dialogVisible"
  77. v-model="dialogVisible"
  78. :id="editId"
  79. :addRowData="addRowData"
  80. @confirm="getList"
  81. />
  82. </template>
  83. <script setup lang="ts">
  84. import { ref, defineProps, defineEmits , watch,onMounted, reactive,onBeforeUnmount } from 'vue'
  85. import EditDialog from "./EditDialog.vue";
  86. import { ElMessage, ElMessageBox } from 'element-plus';
  87. import { Rank, Warning } from '@element-plus/icons-vue';
  88. import client from "@/stores/modules/client";
  89. import icpList from '@/utils/ipc';
  90. import tokenInfo from '@/stores/modules/token';
  91. const clientStore = client();
  92. import socket from "@/stores/modules/socket";
  93. const socketStore = socket(); // WebSocket状态管理实例
  94. const tokenInfoStore = tokenInfo();
  95. import { getTopTabs, getDeviceConfigs,setLeftRightConfig,restConfig,sortDeviceConfig,setTabName,delDviceConfig } from '@/apis/setting'
  96. // 表格数据和对话框状态
  97. const tableData = ref([]); // 配置表格数据
  98. const dialogVisible = ref(false); // 编辑对话框可见状态
  99. const editTitle = ref(''); // 编辑对话框标题
  100. const addRowData = ref({}); // 新增行
  101. const topsTab = ref('left'); // 顶部tab
  102. const activeTab = ref({}); // 当前激活的标签页
  103. const tabs = ref([]); // 所有标签页
  104. const editId = ref(0); // 当前编辑行的索引
  105. const selectID = ref(0) //当前默认的ID
  106. const isSortMode = ref(false); // 是否处于排序模式
  107. const originalTableData = ref([]); // 保存原始数据用于排序
  108. const tableRef = ref(null); // 表格引用
  109. let dragEventHandlers = null; // 拖拽事件处理器
  110. onBeforeUnmount(()=>{
  111. window.removeEventListener('beforeunload', handleBeforeUnload);
  112. // 清理排序模式
  113. if (isSortMode.value) {
  114. exitSortMode();
  115. }
  116. })
  117. onMounted(()=>{
  118. window.addEventListener('beforeunload', handleBeforeUnload);
  119. topsTab.value = 'left';
  120. getTopList()
  121. })
  122. const handleBeforeUnload = (e)=>{
  123. if(dialogVisible.value){
  124. // 没有token时,直接关闭实时预览,不显示提示
  125. dialogVisible.value = false;
  126. // 调用hideVideo逻辑
  127. hideVideo();
  128. return;
  129. // 检查是否有token
  130. const token = tokenInfoStore.getToken;
  131. if (!token || token.trim() === '') {
  132. // 没有token时,直接关闭实时预览,不显示提示
  133. dialogVisible.value = false;
  134. // 调用hideVideo逻辑
  135. hideVideo();
  136. return;
  137. }
  138. // 有token时,显示提示阻止关闭
  139. e.preventDefault();
  140. const message = '您已打开实时预览弹出框,请先取消或者保存后,关闭编辑弹出框,后再关闭此窗口';
  141. e.returnValue = message; // 标准方式
  142. ElMessage.error('您已打开实时预览弹出框,请先取消或者保存后,关闭编辑弹出框,后再关闭此窗口,')
  143. return message; // 兼容某些浏览器
  144. }
  145. }
  146. // 添加hideVideo函数
  147. function hideVideo(){
  148. clientStore.ipc.removeAllListeners(icpList.camera.PreviewHide);
  149. clientStore.ipc.send(icpList.camera.PreviewHide);
  150. clientStore.ipc.on(icpList.camera.PreviewHide, async () => {
  151. // 这里可以添加清理逻辑,比如清除定时器等
  152. })
  153. }
  154. /**
  155. * 监听topsTab变化,获取对应标签页的设备配置列表。
  156. */
  157. watch(() => topsTab.value, (newTab) => {
  158. if (!isSortMode.value) {
  159. getTopList();
  160. }
  161. });
  162. const getTopList = async ()=>{
  163. const result = await getTopTabs({
  164. type: topsTab.value == 'left' ? 0 :1
  165. })
  166. if(result.code == 0 && result.data){
  167. tabs.value = result.data.tabs
  168. tabs.value.some(item=>{
  169. if(item.id === result.data.select_configs[topsTab.value]){
  170. selectID.value = item.id
  171. activeTab.value = item
  172. return true;
  173. }
  174. })
  175. if(!selectID.value){
  176. selectID.value = tabs.value[0].id
  177. activeTab.value = tabs.value[0]
  178. }
  179. getList()
  180. }
  181. }
  182. //切换tab
  183. const toggleTab = (item) => {
  184. if (isSortMode.value) return; // 排序模式下禁用
  185. activeTab.value = item
  186. getList()
  187. };
  188. const calibrationId = ref(null) //校准位
  189. /**
  190. * 获取设备配置列表。
  191. */
  192. const getList = async () => {
  193. // 如果正在排序模式,先退出
  194. if (isSortMode.value) {
  195. exitSortMode();
  196. }
  197. let params = {
  198. tab_id: activeTab.value.id
  199. }
  200. const result = await getDeviceConfigs(params)
  201. if (result.code == 0) {
  202. tableData.value = result.data.list;
  203. const calibration = result.data.list.filter(item=>(item.action_name === '侧视'))
  204. if(calibration.length >= 1){
  205. calibrationId.value = calibration[0].id
  206. }else{
  207. calibrationId.value = tableData.value[0].id
  208. }
  209. }
  210. };
  211. const changeSelectId = async (e,id)=>{
  212. if (e.target.tagName === 'INPUT') return;
  213. if (isSortMode.value) return; // 排序模式下禁用
  214. if(id === selectID.value) return;
  215. let params = {
  216. type: topsTab.value,
  217. id,
  218. }
  219. const result = await setLeftRightConfig(params)
  220. if (result.code == 0) {
  221. selectID.value = id;
  222. }
  223. }
  224. /**
  225. * 编辑指定行的配置。
  226. * @param {Object} row - 当前行的数据
  227. * @param {number} index - 当前行的索引
  228. */
  229. const editRow = (row, index) => {
  230. if (isSortMode.value) return; // 排序模式下禁用
  231. addRowData.value = {}
  232. dialogVisible.value = true;
  233. editId.value = row.id
  234. };
  235. /**
  236. * 删除指定行的配置。
  237. * @param {Object} row - 当前行的数据
  238. * @param {number} index - 当前行的索引
  239. */
  240. const deleteRow = (row, index) => {
  241. if (isSortMode.value) return; // 排序模式下禁用
  242. ElMessageBox.confirm('确定删除该步骤吗?', '提示', {
  243. confirmButtonText: '确定',
  244. cancelButtonText: '取消',
  245. type: 'warning'
  246. }).then(async () => {
  247. const result = await delDviceConfig({
  248. id: row.id
  249. })
  250. if (result.code == 0) {
  251. getList();
  252. ElMessage.success('删除成功');
  253. }
  254. });
  255. };
  256. /**
  257. * 重置设备配置。
  258. */
  259. const resetConfig = () => {
  260. if (isSortMode.value) return; // 排序模式下禁用
  261. console.log(activeTab.value);
  262. ElMessageBox.confirm(`确定初始化${activeTab.value.mode_name}吗?`, '提示', {
  263. confirmButtonText: '确定',
  264. cancelButtonText: '取消',
  265. type: 'warning'
  266. }).then(async () => {
  267. const result = await restConfig({
  268. tab_id: activeTab.value.id
  269. })
  270. if (result.code == 0) {
  271. getList();
  272. ElMessage.success('重置成功');
  273. }
  274. });
  275. };
  276. const reName = ()=>{
  277. if (isSortMode.value) return; // 排序模式下禁用
  278. ElMessageBox.prompt('', '重命名配置', {
  279. confirmButtonText: '保存',
  280. cancelButtonText: '取消',
  281. inputValue: activeTab.value.mode_name,
  282. inputPlaceholder:'请输入配置名称',
  283. inputValidator: (value) => {
  284. if (value === '') {
  285. return '请输入配置名称';
  286. }
  287. return true;
  288. },
  289. })
  290. .then(async ({ value }) => {
  291. const result = await setTabName({
  292. id: activeTab.value.id,
  293. mode_name:value,
  294. })
  295. if (result.code == 0) {
  296. activeTab.value.mode_name = value
  297. tabs.value.some(item=>{
  298. if(item.id === activeTab.value.id){
  299. item.mode_name = activeTab.value.mode_name
  300. }
  301. })
  302. ElMessage.success('重命名成功');
  303. }
  304. })
  305. }
  306. /**
  307. * 新增一行配置。
  308. */
  309. const addRow = () => {
  310. if (isSortMode.value) return; // 排序模式下禁用
  311. editId.value = -1
  312. let length = Number(tableData.value.length)+1
  313. addRowData.value = {
  314. mode_type: topsTab.value === 'left' ? '执行左脚程序' : '执行右脚程序',
  315. tab_id: activeTab.value.id,
  316. action_name: '新增步骤'+length,
  317. take_picture: false,
  318. camera_height: 0,
  319. camera_angle: 0,
  320. turntable_position: 0,
  321. turntable_angle: 0,
  322. shoe_upturn: false,
  323. led_switch: false,
  324. number_focus: 0,
  325. pre_delay: 0,
  326. after_delay: 0,
  327. }
  328. dialogVisible.value = true;
  329. editTitle.value = '新增步骤';
  330. };
  331. /**
  332. * 切换排序模式
  333. */
  334. const toggleSortMode = () => {
  335. if (isSortMode.value) {
  336. // 保存排序
  337. saveSortOrder();
  338. } else {
  339. // 进入排序模式
  340. enterSortMode();
  341. }
  342. };
  343. /**
  344. * 取消排序
  345. */
  346. const cancelSort = () => {
  347. exitSortMode();
  348. ElMessage.info('已取消排序');
  349. };
  350. /**
  351. * 进入排序模式
  352. */
  353. const enterSortMode = () => {
  354. isSortMode.value = true;
  355. // 保存原始数据
  356. originalTableData.value = JSON.parse(JSON.stringify(tableData.value));
  357. // 为每行添加排序值
  358. tableData.value.forEach((item, index) => {
  359. item.sort = index + 1;
  360. });
  361. // 等待DOM更新后初始化Sortable
  362. setTimeout(() => {
  363. initSortable();
  364. }, 100);
  365. ElMessage.info('请拖拽行进行排序,完成后点击"保存排序"');
  366. };
  367. /**
  368. * 初始化拖拽排序
  369. */
  370. const initSortable = () => {
  371. if (!tableRef.value) return;
  372. const tbody = tableRef.value.$el.querySelector('.el-table__body-wrapper tbody');
  373. if (!tbody) return;
  374. // 使用原生拖拽API实现排序
  375. let draggedRow = null;
  376. let draggedIndex = -1;
  377. // 创建事件处理器
  378. dragEventHandlers = {
  379. handleDragStart: (e) => {
  380. if (!isSortMode.value) return;
  381. draggedRow = e.target.closest('tr');
  382. if (draggedRow) {
  383. e.dataTransfer.effectAllowed = 'move';
  384. draggedRow.style.opacity = '0.5';
  385. const rows = Array.from(tbody.querySelectorAll('tr'));
  386. draggedIndex = rows.indexOf(draggedRow);
  387. }
  388. },
  389. handleDragEnd: (e) => {
  390. if (draggedRow) {
  391. draggedRow.style.opacity = '';
  392. draggedRow = null;
  393. draggedIndex = -1;
  394. }
  395. },
  396. handleDragOver: (e) => {
  397. if (!isSortMode.value || !draggedRow) return;
  398. e.preventDefault();
  399. e.dataTransfer.dropEffect = 'move';
  400. },
  401. handleDrop: (e) => {
  402. if (!isSortMode.value || !draggedRow) return;
  403. e.preventDefault();
  404. const dropRow = e.target.closest('tr');
  405. if (!dropRow || dropRow === draggedRow) return;
  406. // 获取目标行的索引
  407. const rows = Array.from(tbody.querySelectorAll('tr'));
  408. const dropIndex = rows.indexOf(dropRow);
  409. if (draggedIndex !== -1 && dropIndex !== -1 && draggedIndex !== dropIndex) {
  410. // 重新排序数据
  411. const newData = [...tableData.value];
  412. const [draggedItem] = newData.splice(draggedIndex, 1);
  413. newData.splice(dropIndex, 0, draggedItem);
  414. // 更新排序值
  415. newData.forEach((item, index) => {
  416. item.sort = index + 1;
  417. });
  418. tableData.value = newData;
  419. }
  420. }
  421. };
  422. // 添加事件监听器
  423. tbody.addEventListener('dragstart', dragEventHandlers.handleDragStart);
  424. tbody.addEventListener('dragend', dragEventHandlers.handleDragEnd);
  425. tbody.addEventListener('dragover', dragEventHandlers.handleDragOver);
  426. tbody.addEventListener('drop', dragEventHandlers.handleDrop);
  427. // 为每行添加拖拽属性
  428. const rows = tbody.querySelectorAll('tr');
  429. rows.forEach(row => {
  430. row.draggable = isSortMode.value;
  431. });
  432. };
  433. /**
  434. * 保存排序
  435. */
  436. const saveSortOrder = async () => {
  437. // 准备排序数据
  438. const sortData = tableData.value.map((item, index) => ({
  439. id: item.id,
  440. action_index: index + 1
  441. }));
  442. console.log("sort_data",sortData)
  443. const result = await sortDeviceConfig({
  444. sorts: sortData
  445. })
  446. if (result.code == 0) {
  447. getList();
  448. ElMessage.success('排序成功');
  449. }
  450. };
  451. /**
  452. * 获取行类名
  453. */
  454. const getRowClassName = ({ row, rowIndex }) => {
  455. if (isSortMode.value) {
  456. return 'sortable-row';
  457. }
  458. return '';
  459. };
  460. /**
  461. * 退出排序模式
  462. */
  463. const exitSortMode = () => {
  464. isSortMode.value = false;
  465. // 恢复原始数据
  466. tableData.value = JSON.parse(JSON.stringify(originalTableData.value));
  467. // 移除拖拽事件监听器和属性
  468. if (tableRef.value && dragEventHandlers) {
  469. const tbody = tableRef.value.$el.querySelector('.el-table__body-wrapper tbody');
  470. if (tbody) {
  471. // 移除事件监听器
  472. tbody.removeEventListener('dragstart', dragEventHandlers.handleDragStart);
  473. tbody.removeEventListener('dragend', dragEventHandlers.handleDragEnd);
  474. tbody.removeEventListener('dragover', dragEventHandlers.handleDragOver);
  475. tbody.removeEventListener('drop', dragEventHandlers.handleDrop);
  476. // 移除拖拽属性
  477. const rows = tbody.querySelectorAll('tr');
  478. rows.forEach(row => {
  479. row.draggable = false;
  480. });
  481. }
  482. dragEventHandlers = null;
  483. }
  484. };
  485. </script>
  486. <style lang="scss" scoped>
  487. .top_tabs {
  488. height: 40px;
  489. overflow: hidden;
  490. border: 1px solid #c8c8c8;
  491. border-bottom: none;
  492. ::v-deep {
  493. .el-tabs__item {
  494. height: 40px;
  495. line-height: 40px;
  496. padding: 0 15px;
  497. font-size: 14px;
  498. color: #333;
  499. &.is-active {
  500. color: #2957FF;
  501. }
  502. }
  503. }
  504. }
  505. .two_tabs {
  506. width: 100%;
  507. height: 30px;
  508. background: #fff;
  509. border: 1px solid #c8c8c8;
  510. border-top: none;
  511. .item {
  512. float: left;
  513. padding: 0 15px;
  514. font-size: 14px;
  515. height: 30px;
  516. line-height: 30px;
  517. cursor: pointer;
  518. &.active {
  519. color: #2957FF;
  520. }
  521. }
  522. }
  523. .form-table{
  524. margin-top: 10px;
  525. .btnBox{
  526. display: flex;
  527. align-items: center;
  528. margin-bottom: 12px;
  529. }
  530. :deep(.el-table .el-table__header){
  531. padding: 0;
  532. height: 30px;
  533. .el-table__cell{
  534. background: #F1F4FF;
  535. }
  536. }
  537. :deep(.el-table .el-table__cell){
  538. padding: 0;
  539. text-align: center;
  540. }
  541. :deep(.el-table__row) {
  542. height: 30px;
  543. padding: 0;
  544. &:nth-child(even) {
  545. background: #F1F4FF;
  546. }
  547. &:nth-child(odd) {
  548. background: #FFFFFF;
  549. }
  550. }
  551. .primary-btn{
  552. width: 80px;
  553. height: 30px;
  554. background: linear-gradient( 135deg, #2FB0FF 0%, #B863FB 100%);
  555. border-radius: 4px;
  556. color: #fff;
  557. font-size: 14px;
  558. text-align: center;
  559. cursor: pointer;
  560. line-height: 30px;
  561. margin-right: 10px;
  562. }
  563. .normal-btn{
  564. width: 80px;
  565. height: 30px;
  566. background: #fff;
  567. border: 1px solid #CCCCCC;
  568. border-radius: 4px;
  569. font-size: 14px;
  570. text-align: center;
  571. line-height: 30px;
  572. cursor: pointer;
  573. }
  574. .cursor-pointer{
  575. cursor: pointer;
  576. }
  577. // 排序相关样式
  578. .sort-content {
  579. display: flex;
  580. align-items: center;
  581. justify-content: space-between;
  582. height: 100%;
  583. .sort-number {
  584. font-weight: bold;
  585. color: #2957FF;
  586. font-size: 14px;
  587. }
  588. .sort-handle {
  589. cursor: move;
  590. color: #909399;
  591. display: flex;
  592. align-items: center;
  593. justify-content: center;
  594. &:hover {
  595. color: #2957FF;
  596. }
  597. }
  598. }
  599. :deep(.sortable-row) {
  600. cursor: move;
  601. &:hover {
  602. background-color: #f5f7fa !important;
  603. }
  604. }
  605. :deep(.el-table__row.sortable-row) {
  606. transition: all 0.3s ease;
  607. }
  608. :deep(.el-table__body-wrapper tbody tr) {
  609. &.sortable-row {
  610. cursor: move;
  611. &:hover {
  612. background-color: #f5f7fa !important;
  613. }
  614. }
  615. }
  616. .disabled {
  617. pointer-events: none;
  618. }
  619. .sort-tip {
  620. background: #EAF3FF;
  621. border: 1px solid #CBE1FF;
  622. border-radius: 4px;
  623. padding: 8px 12px;
  624. margin-bottom: 12px;
  625. display: flex;
  626. align-items: center;
  627. gap: 8px;
  628. color: #2957FF;
  629. font-size: 14px;
  630. }
  631. }
  632. .editDialog{
  633. .el-dialog__body{
  634. padding: 0 !important;
  635. }
  636. .btn-row{
  637. display: flex;
  638. align-items: center;
  639. justify-content: flex-end;
  640. gap: 10px;
  641. }
  642. .primary-btn{
  643. width: 100px;
  644. height: 30px;
  645. background: linear-gradient( 135deg, #2FB0FF 0%, #B863FB 100%);
  646. border-radius: 4px;
  647. color: #fff;
  648. font-size: 14px;
  649. text-align: center;
  650. line-height: 30px;
  651. cursor: pointer;
  652. }
  653. .normal-btn{
  654. width: 100px;
  655. height: 30px;
  656. background: #fff;
  657. border: 1px solid #CCCCCC;
  658. border-radius: 4px;
  659. font-size: 14px;
  660. text-align: center;
  661. line-height: 30px;
  662. cursor: pointer;
  663. }
  664. }
  665. </style>