index.vue 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897
  1. <template>
  2. <headerBar
  3. title="设置"
  4. />
  5. <div class="container">
  6. <nav class="settings-nav">
  7. <div class="nav-item" :class="{'active': activeIndex === 0}" @click="activeIndex = 0">
  8. <img src="@/assets/images/setting/icon1.png" class="nav-icon" v-if="activeIndex !== 0"/>
  9. <img src="@/assets/images/setting/icon1a.png" class="nav-icon" v-else/>
  10. <span>基础配置</span>
  11. </div>
  12. <div class="nav-item" :class="{'active': activeIndex === 2}" @click="activeIndex = 2">
  13. <img src="@/assets/images/setting/icon3.png" class="nav-icon" v-if="activeIndex !== 2"/>
  14. <img src="@/assets/images/setting/icon3a.png" class="nav-icon" v-else/>
  15. <span>其他设置</span>
  16. </div>
  17. <div class="nav-item" :class="{'active': activeIndex === 4}" @click="activeIndex = 4">
  18. <img src="@/assets/images/setting/icon4.png" class="nav-icon" v-if="activeIndex !== 4"/>
  19. <img src="@/assets/images/setting/icon4a.png" class="nav-icon" v-else/>
  20. <span>左右脚程序设置</span>
  21. </div>
  22. </nav>
  23. <div class="form-container">
  24. <!--基础配置-->
  25. <div class="selectBox" v-if="activeIndex === 0">
  26. <div class="form-item">
  27. <label>主图尺寸:</label>
  28. <div class="select-wrapper">
  29. <el-select v-model="formData.basic_configs.main_image_size" placeholder="请选择">
  30. <el-option v-for="item in mainImageSizeList" :key="item.value" :label="item.label" :value="item.value"></el-option>
  31. </el-select>
  32. </div>
  33. </div>
  34. <div class="form-item">
  35. <label>图片输出格式:</label>
  36. <div class="select-wrapper">
  37. <el-select v-model="formData.basic_configs.image_out_format" placeholder="请选择">
  38. <el-option v-for="item in imageFormatList" :key="item.value" :label="item.label" :value="item.value"></el-option>
  39. </el-select>
  40. </div>
  41. </div>
  42. <div class="form-item">
  43. <label>图片锐化:</label>
  44. <div class="select-wrapper">
  45. <el-select v-model="formData.basic_configs.image_sharpening" placeholder="请选择">
  46. <el-option v-for="item in imageSharpeningList" :key="item.value" :label="item.label" :value="item.value"></el-option>
  47. </el-select>
  48. </div>
  49. </div>
  50. </div>
  51. <!--基础配置-->
  52. <!--其他设置-->
  53. <div class="selectBox" style="padding-top: 0px" v-if="activeIndex === 2">
  54. <div class="form-item">
  55. <label>产品类型:</label>
  56. <div class="select-wrapper">
  57. <el-select v-model="formData.other_configs.product_type" placeholder="请选择">
  58. <el-option v-for="item in productTypeList" :key="item.value" :label="item.label" :value="item.value"></el-option>
  59. </el-select>
  60. </div>
  61. </div>
  62. <div class="form-item">
  63. <label>默认抠图模式:</label>
  64. <div class="select-wrapper">
  65. <el-select v-model="formData.other_configs.cutout_mode" placeholder="请选择">
  66. <el-option v-for="item in defaultCutoutModeList" :key="item.value" :label="item.label" :value="item.value"></el-option>
  67. </el-select>
  68. </div>
  69. </div>
  70. <div class="form-item">
  71. <label>设备运动速度:</label>
  72. <div class="select-wrapper">
  73. <el-select v-model="formData.other_configs.device_speed" placeholder="请选择">
  74. <el-option v-for="item in deviceSpeedList" :key="item.value" :label="item.label" :value="item.value"></el-option>
  75. </el-select>
  76. </div>
  77. </div>
  78. <!-- <div class="form-item">
  79. <label>运行模式:</label>
  80. <div class="select-wrapper">
  81. <el-select v-model="formData.other_configs.running_mode" placeholder="请选择">
  82. <el-option v-for="item in runModeList" :key="item.value" :label="item.label" :value="item.value"></el-option>
  83. </el-select>
  84. </div>
  85. </div>-->
  86. </div>
  87. <!--其他设置-->
  88. <div class="selectBox" style="padding-top: 0px;padding-left: 0;" v-if="activeIndex === 4">
  89. <el-tabs v-model="activeTab" type="card">
  90. <el-tab-pane label="执行左脚程序" name="left">
  91. </el-tab-pane>
  92. <el-tab-pane label="执行右脚程序" name="right"></el-tab-pane>
  93. </el-tabs>
  94. <div class="form-table">
  95. <div class="btnBox">
  96. <div class="primary-btn" @click="addRow">新增一行</div>
  97. <div class="normal-btn" @click="resetConfig">重新初始化</div>
  98. </div>
  99. <el-table max-height="700" :data="activeTab === 'left' ? lefttableData : righttableData" style="width: 100%" border>
  100. <el-table-column prop="id" label="id" />
  101. <el-table-column prop="action_name" label="步骤" />
  102. <el-table-column prop="take_picture" label="是否拍照" width="200px">
  103. <template #default="scope">
  104. <el-radio-group v-model="scope.row.take_picture" v-if="!scope.row.is_system">
  105. <el-radio :label="true">拍照</el-radio>
  106. <el-radio :label="false">不拍照</el-radio>
  107. </el-radio-group>
  108. <span v-else></span>
  109. </template>
  110. </el-table-column>
  111. <!-- <el-table-column prop="action_index" label="排序" >
  112. <template #default="{row, $index}">
  113. <a v-if="$index !== 0" class="cursor-pointer" @click="upRow(row)">上移</a>
  114. <a class="mar-left-10 cursor-pointer" v-if="$index !== activeTab === 'left' ? lefttableData.length - 1 : righttableData.length - 1" @click="downRow(row)">下移</a>
  115. </template>
  116. </el-table-column>-->
  117. <el-table-column prop="value" label="操作" >
  118. <template #default="{row, $index}">
  119. <a class="mar-right-10 cursor-pointer" @click="editRow(row, $index)">编辑</a>
  120. <a class="cursor-pointer" v-if="!row.is_system" @click="deleteRow(row, $index)">删除</a>
  121. </template>
  122. </el-table-column>
  123. </el-table>
  124. </div>
  125. </div>
  126. </div>
  127. <div class="text-center mt-8">
  128. <button class="bg-gradient-to-r from-primary" @click="saveSetting(activeIndex)" v-if="activeIndex !== 4">
  129. 保存
  130. </button>
  131. </div>
  132. <EditDialog
  133. v-if="dialogVisible"
  134. v-model="dialogVisible"
  135. :id="editId"
  136. :addRowData="addRowData"
  137. @confirm="getList"
  138. />
  139. </div>
  140. </template>
  141. <script setup>
  142. /**
  143. * Vue组件逻辑部分,包含与设备配置相关的功能。
  144. * 主要功能包括:表单数据管理、设备配置列表获取、新增/编辑/删除步骤、保存配置等。
  145. */
  146. // 引入Vue相关功能和第三方库
  147. import { ref, reactive } from 'vue';
  148. import { useRoute, useRouter } from 'vue-router';
  149. import { onMounted, watch } from 'vue';
  150. import socket from "@/stores/modules/socket";
  151. import headerBar from '@/components/header-bar/index.vue';
  152. import EditDialog from './components/EditDialog'
  153. import client from "@/stores/modules/client";
  154. import icpList from '@/utils/ipc';
  155. const clientStore = client();
  156. import { ElMessage, ElMessageBox } from 'element-plus';
  157. import { digiCamControlWEB } from '@/utils/appconfig'
  158. import { useCheckInfo } from '@/composables/userCheck';
  159. import { preview } from '@planckdev/element-plus/utils'
  160. useCheckInfo();
  161. // 路由和状态管理初始化
  162. const route = useRoute();
  163. const router = useRouter();
  164. // 定义响应式变量
  165. const folderPath = ref(''); // 文件夹路径
  166. const activeIndex = ref(0); // 当前激活的索引
  167. const socketStore = socket(); // WebSocket状态管理实例
  168. /**
  169. * 表单数据对象,用于存储设备配置信息。
  170. */
  171. const formData = reactive({
  172. //基础配置
  173. basic_configs:{
  174. "main_image_size": "",//主图尺寸
  175. "image_out_format": "",//图片输出格式
  176. "image_sharpening": "" //图片锐化
  177. },
  178. //拍照配置
  179. take_photo_configs:{
  180. "repart_take_photo_warning": false,//重复拍摄警告
  181. "single_photo_warning": "",//单次张数警告
  182. "total_photo_warning": "",//累计拍照警告
  183. "camera_delay": ""//拍照停留
  184. },
  185. other_configs:{
  186. "product_type": "",//产品类型
  187. "cutout_mode": "",//默认抠图模式
  188. "device_speed": "",//设备运动速度
  189. "running_mode": "" //运行模式
  190. },
  191. captureOneFolder: '', // Capture One文件夹路径
  192. mainImageSize: '', // 主图尺寸
  193. imageFormat: '', // 图片格式
  194. imageSharpening: '', // 图片锐化
  195. repeatWarning: '', // 重复警告
  196. singleWarning: '', // 单次警告
  197. totalWarning: '', // 总警告
  198. focusTime: '', // 对焦时间
  199. photoTime: '', // 拍照时间
  200. productType: '', // 产品类型
  201. defaultCutoutMode: '', // 默认抠图模式
  202. deviceSpeed: '', // 设备速度
  203. runMode: '', // 运行模式
  204. receiver: '', // 接收器类型
  205. left: '', // 左脚配置
  206. right: '', // 右脚配置
  207. up: '', // 上移配置
  208. down: '', // 下移配置
  209. });
  210. // 配置选项列表
  211. const mainImageSizeList = ref([
  212. { label: '800', value: '800' },
  213. { label: '1024', value: '1024' },
  214. { label: '1200', value: '1200' },
  215. { label: '1600', value: '1600' },
  216. ]);
  217. const imageFormatList = ref([
  218. { label: 'jpg', value: 'jpg' },
  219. { label: 'png', value: 'png' },
  220. { label: 'jpeg', value: 'jpeg' },
  221. ]);
  222. const imageSharpeningList = ref([
  223. { label: '0', value: '0' },
  224. { label: '1', value: '1' },
  225. { label: '2', value: '2' },
  226. { label: '3', value: '3' },
  227. ]);
  228. const repeatWarningList = ref([
  229. { label: '关闭', value: false },
  230. { label: '开启', value: true },
  231. ]);
  232. const singleWarningList = ref([
  233. { label: '11', value: '11' },
  234. { label: '12', value: '12' },
  235. { label: '13', value: '13' },
  236. ]);
  237. const totalWarningList = ref([
  238. { label: '1.0', value: '1.0' },
  239. { label: '1.5', value: '1.5' },
  240. { label: '2.0', value: '2.0' },
  241. ]);
  242. const productTypeList = ref([
  243. { label: '鞋类', value: '鞋类' },
  244. { label: '服装', value: '服装' },
  245. { label: '箱包', value: '箱包' },
  246. ]);
  247. const defaultCutoutModeList = ref([
  248. { label: '普通抠图', value: '普通抠图' },
  249. { label: '精细化抠图', value: '精细化抠图' },
  250. ]);
  251. const deviceSpeedList = ref([
  252. { label: '一档', value: '1' },
  253. { label: '二档', value: '2' },
  254. { label: '三档', value: '3' },
  255. ]);
  256. const runModeList = ref([
  257. { label: '普通模式', value: '普通模式' },
  258. { label: '待用户确认模式', value: '待用户确认模式' }
  259. ]);
  260. const receiverList = ref([
  261. { label: '蓝牙', value: '1' },
  262. { label: '2.4G', value: '2' },
  263. { label: '5.8G', value: '3' },
  264. ]);
  265. const leftList = ref([
  266. { label: '左脚', value: '1' },
  267. { label: '右脚', value: '2' },
  268. { label: '左右脚', value: '3' },
  269. ]);
  270. const rightList = ref([
  271. { label: '左脚', value: '1' },
  272. { label: '右脚', value: '2' },
  273. { label: '左右脚', value: '3' },
  274. ]);
  275. const upList = ref([
  276. { label: '上移', value: '1' },
  277. { label: '下移', value: '2' },
  278. { label: '左右移', value: '3' },
  279. ]);
  280. const downList = ref([
  281. { label: '上移', value: '1' },
  282. { label: '下移', value: '2' },
  283. { label: '左右移', value: '3' },
  284. ]);
  285. // 表格数据和对话框状态
  286. const lefttableData = ref([]); // 左脚配置表格数据
  287. const righttableData = ref([]); // 右脚配置表格数据
  288. const dialogVisible = ref(false); // 编辑对话框可见状态
  289. const editTitle = ref(''); // 编辑对话框标题
  290. const addRowData = ref({}); // 新增行
  291. const activeTab = ref('left'); // 当前激活的标签页
  292. const editId = ref(0); // 当前编辑行的索引
  293. const isDefault = ref(false); // 是否为默认配置
  294. const indexKey ={
  295. 0:"basic_configs",
  296. 1:"take_photo_configs",
  297. 2:"other_configs",
  298. }
  299. /**
  300. * 监听路由参数变化,更新activeIndex和activeTab。
  301. */
  302. watch(() => route.query.type, async (newType,oldType) => {
  303. if(['0','1','2'].includes(oldType)){
  304. await saveSetting(oldType)
  305. }
  306. const typeValue = parseInt(newType) || 0;
  307. switch (typeValue) {
  308. case 4:
  309. activeTab.value = 'left';
  310. clientStore.ipc.removeAllListeners(icpList.setting.getDeviceConfigList);
  311. clientStore.ipc.send(icpList.setting.getDeviceConfigList, {
  312. mode_type: '执行左脚程序'
  313. });
  314. clientStore.ipc.on(icpList.setting.getDeviceConfigList, (event, result) => {
  315. if (result?.data?.list) {
  316. lefttableData.value = result.data.list;
  317. }
  318. clientStore.ipc.removeAllListeners(icpList.setting.getDeviceConfigList);
  319. });
  320. break;
  321. default:
  322. clientStore.ipc.removeAllListeners(icpList.setting.getSysConfig);
  323. clientStore.ipc.send(icpList.setting.getSysConfig,{
  324. key: indexKey[typeValue]
  325. });
  326. clientStore.ipc.on(icpList.setting.getSysConfig, (event, result) => {
  327. if(result.code == 0 && result.data){
  328. formData[indexKey[typeValue]] = result.data
  329. }
  330. console.log('icpList.setting.getSysConfig')
  331. console.log(result)
  332. clientStore.ipc.removeAllListeners(icpList.setting.getSysConfig);
  333. });
  334. break;
  335. }
  336. }, { immediate: true });
  337. /**
  338. * 监听activeTab变化,获取对应标签页的设备配置列表。
  339. */
  340. watch(() => activeTab.value, (newTab) => {
  341. if (newTab === 'left') {
  342. clientStore.ipc.removeAllListeners(icpList.setting.getDeviceConfigList);
  343. clientStore.ipc.send(icpList.setting.getDeviceConfigList, {
  344. mode_type: '执行左脚程序'
  345. });
  346. clientStore.ipc.on(icpList.setting.getDeviceConfigList, (event, result) => {
  347. if (result?.data?.list) {
  348. lefttableData.value = result.data.list;
  349. }
  350. clientStore.ipc.removeAllListeners(icpList.setting.getDeviceConfigList);
  351. });
  352. } else {
  353. clientStore.ipc.removeAllListeners(icpList.setting.getDeviceConfigList);
  354. clientStore.ipc.send(icpList.setting.getDeviceConfigList, {
  355. mode_type: '执行右脚程序'
  356. });
  357. clientStore.ipc.on(icpList.setting.getDeviceConfigList, (event, result) => {
  358. if (result?.data?.list) {
  359. righttableData.value = result.data.list;
  360. }
  361. clientStore.ipc.removeAllListeners(icpList.setting.getDeviceConfigList);
  362. });
  363. }
  364. });
  365. /**
  366. * 监听activeIndex变化,更新URL中的查询参数。
  367. */
  368. watch(() => activeIndex.value, (newIndex) => {
  369. router.push({
  370. query: {
  371. ...route.query,
  372. type: newIndex.toString()
  373. }
  374. });
  375. });
  376. /**
  377. * 组件挂载时初始化activeIndex。
  378. */
  379. onMounted(() => {
  380. if (route.query.type) {
  381. const typeValue = parseInt(route.query.type);
  382. if (!isNaN(typeValue) && typeValue >= 0 && typeValue <= 3) {
  383. activeIndex.value = typeValue;
  384. }
  385. }
  386. });
  387. /**
  388. * 打开文件夹选择对话框并更新表单数据。
  389. */
  390. const selectFolder = () => {
  391. clientStore.ipc.removeAllListeners(icpList.utils.openDirectory);
  392. clientStore.ipc.send(icpList.utils.openDirectory);
  393. clientStore.ipc.on(icpList.utils.openDirectory, async (event, result) => {
  394. formData.captureOneFolder = result;
  395. clientStore.ipc.removeAllListeners(icpList.utils.openDirectory);
  396. });
  397. };
  398. /**
  399. * 保存当前表单配置。
  400. */
  401. const saveSetting = async (index) => {
  402. await new Promise((resolve, reject) => {
  403. clientStore.ipc.removeAllListeners(icpList.setting.updateSysConfigs);
  404. clientStore.ipc.send(icpList.setting.updateSysConfigs,{
  405. key: indexKey[index],
  406. value:JSON.stringify({
  407. ...formData[indexKey[index]]
  408. })
  409. });
  410. clientStore.ipc.on(icpList.setting.updateSysConfigs, async (event, result) => {
  411. clientStore.ipc.removeAllListeners(icpList.setting.updateSysConfigs);
  412. if(result.code === 0 && result.msg){
  413. resolve(result)
  414. }
  415. });
  416. });
  417. };
  418. /**
  419. * 新增一行配置。
  420. */
  421. const addRow = () => {
  422. if (activeTab.value === 'left') {
  423. editId.value = -1
  424. addRowData.value = {
  425. mode_type: '执行左脚程序',
  426. action_name: '',
  427. take_picture: false,
  428. camera_height: 0,
  429. camera_angle: 0,
  430. turntable_position: 0,
  431. turntable_angle: 0,
  432. shoe_upturn: false,
  433. led_switch: false,
  434. number_focus: 0,
  435. pre_delay: 0,
  436. after_delay: 0,
  437. };
  438. dialogVisible.value = true;
  439. editTitle.value = '新增步骤';
  440. } else {
  441. editId.value = -1
  442. addRowData.value = {
  443. mode_type: '执行右脚程序',
  444. action_name: '',
  445. take_picture: false,
  446. camera_height: 0,
  447. camera_angle: 0,
  448. turntable_position: 0,
  449. turntable_angle: 0,
  450. shoe_upturn: false,
  451. led_switch: false,
  452. number_focus: 0,
  453. pre_delay: 0,
  454. after_delay: 0,
  455. };
  456. dialogVisible.value = true;
  457. editTitle.value = '新增步骤';
  458. }
  459. };
  460. /**
  461. * 获取设备配置列表。
  462. */
  463. const getList = () => {
  464. clientStore.ipc.removeAllListeners(icpList.setting.getDeviceConfigList);
  465. clientStore.ipc.send(icpList.setting.getDeviceConfigList, {
  466. mode_type: activeTab.value === 'left' ? '执行左脚程序' : '执行右脚程序'
  467. });
  468. clientStore.ipc.on(icpList.setting.getDeviceConfigList, (event, result) => {
  469. if (result.code == 0) {
  470. if (activeTab.value === 'left') {
  471. lefttableData.value = result.data.list;
  472. } else {
  473. righttableData.value = result.data.list;
  474. }
  475. } else {
  476. ElMessage.error('获取列表失败');
  477. }
  478. clientStore.ipc.removeAllListeners(icpList.setting.getDeviceConfigList);
  479. });
  480. };
  481. /**
  482. * 编辑指定行的配置。
  483. * @param {Object} row - 当前行的数据
  484. * @param {number} index - 当前行的索引
  485. */
  486. const editRow = (row, index) => {
  487. dialogVisible.value = true;
  488. editId.value = row.id
  489. };
  490. /**
  491. * 删除指定行的配置。
  492. * @param {Object} row - 当前行的数据
  493. * @param {number} index - 当前行的索引
  494. */
  495. const deleteRow = (row, index) => {
  496. ElMessageBox.confirm('确定删除该步骤吗?', '提示', {
  497. confirmButtonText: '确定',
  498. cancelButtonText: '取消',
  499. type: 'warning'
  500. }).then(() => {
  501. clientStore.ipc.send(icpList.setting.removeDeviceConfig, {
  502. id: row.id
  503. });
  504. clientStore.ipc.on(icpList.setting.removeDeviceConfig, (event, result) => {
  505. if (result.code == 0) {
  506. getList();
  507. ElMessage.success('删除成功');
  508. } else {
  509. ElMessage.error('删除失败');
  510. }
  511. clientStore.ipc.removeAllListeners(icpList.setting.removeDeviceConfig);
  512. });
  513. });
  514. };
  515. /**
  516. * 重置设备配置。
  517. */
  518. const resetConfig = () => {
  519. ElMessageBox.confirm(`确定初始化执行${activeTab.value === 'left' ? '左脚' : '右脚'}程序吗?`, '提示', {
  520. confirmButtonText: '确定',
  521. cancelButtonText: '取消',
  522. type: 'warning'
  523. }).then(() => {
  524. clientStore.ipc.send(icpList.setting.resetDeviceConfig, {
  525. mode_type: activeTab.value === 'left' ? '执行左脚程序' : '执行右脚程序'
  526. });
  527. clientStore.ipc.on(icpList.setting.resetDeviceConfig, (event, result) => {
  528. if (result.code == 0) {
  529. getList();
  530. ElMessage.success('重置成功');
  531. } else {
  532. ElMessage.error('重置失败');
  533. }
  534. clientStore.ipc.removeAllListeners(icpList.setting.resetDeviceConfig);
  535. });
  536. });
  537. };
  538. </script>
  539. <style lang="scss">
  540. .el-image-viewer__wrapper{
  541. z-index: 9999 !important;
  542. }
  543. </style>
  544. <style lang="scss" scoped>
  545. body {
  546. background: #EAECED;
  547. }
  548. .container {
  549. margin: 0 auto;
  550. min-height: calc(100vh - 30px);
  551. background: #EAECED;
  552. display: flex;
  553. flex-direction: column;
  554. justify-content: flex-start;
  555. }
  556. .settings-nav {
  557. display: flex;
  558. justify-content: center;
  559. gap: 40px;
  560. padding: 30px 0;
  561. background: #EDEFF0;
  562. border-bottom: 1px solid rgba(0,0,0,0.1);
  563. }
  564. .nav-item {
  565. display: flex;
  566. flex-direction: column;
  567. align-items: center;
  568. cursor: pointer;
  569. color: #666;
  570. transition: all 0.3s;
  571. width: 100px;
  572. justify-content: center;
  573. height: 70px;
  574. font-size: 14px;
  575. }
  576. .nav-item.active {
  577. background: #DFE2E3;
  578. border-radius: 10px;
  579. color: #2957FF;
  580. }
  581. .nav-item i {
  582. font-size: 24px;
  583. margin-bottom: 8px;
  584. width: 40px;
  585. height: 40px;
  586. display: flex;
  587. justify-content: center;
  588. align-items: center;
  589. background: #fff;
  590. border-radius: 8px;
  591. }
  592. .form-container {
  593. border-radius: 12px;
  594. padding: 30px;
  595. padding-top: 10px;
  596. width: 800px;
  597. margin: 0 auto;
  598. height: 306px;
  599. }
  600. .form-item {
  601. margin-bottom: 24px;
  602. display: flex;
  603. align-items: center;
  604. }
  605. .form-item label {
  606. display: block;
  607. min-width: 98px;
  608. text-align: right;
  609. font-size: 14px;
  610. color: #1A1A1A;
  611. }
  612. .input-group {
  613. display: flex;
  614. gap: 12px;
  615. }
  616. .input-group input {
  617. flex: 1;
  618. border: 1px solid #e5e7eb;
  619. border-radius: 4px;
  620. padding: 8px 12px;
  621. font-size: 14px;
  622. }
  623. .select-wrapper {
  624. position: relative;
  625. width: 200px;
  626. :deep(.el-input__inner){
  627. border-radius: 6px;
  628. }
  629. }
  630. .error-text {
  631. color: #dc2626;
  632. font-size: 12px;
  633. margin-top: 4px;
  634. }
  635. .from-primary{
  636. width: 150px;
  637. height: 40px;
  638. color: #FFFFFF;
  639. background: linear-gradient( 135deg, #2FB0FF 0%, #B863FB 100%);
  640. }
  641. .nav-icon{
  642. width: 32px;
  643. height: 32px;
  644. }
  645. .captureBox{
  646. border-bottom: 1px solid rgba(0,0,0,0.1);
  647. }
  648. .selectBox{
  649. padding-top: 30px;
  650. padding-left: 100px;
  651. border-bottom: 1px solid rgba(0,0,0,0.1);
  652. :deep(.el-tabs__header){
  653. padding-left: 0;
  654. }
  655. :deep(.el-tabs--card>.el-tabs__header){
  656. border-bottom: 1px solid #CCCCCC;
  657. }
  658. :deep(.el-tabs__item){
  659. height: 30px;
  660. line-height: 30px;
  661. }
  662. :deep(.el-tabs__nav-wrap){
  663. margin-bottom: 0;
  664. }
  665. :deep(.el-tabs__item.is-active){
  666. color: #333;
  667. font-weight: bold;
  668. background: #fff;
  669. }
  670. }
  671. .select-btn{
  672. display: flex;
  673. align-items: center;
  674. flex-shrink: 0;
  675. width: 120px;
  676. height: 30px;
  677. background: #DFE2E3;
  678. border-radius: 6px;
  679. justify-content: center;
  680. font-size: 14px;
  681. color: #2957FF;
  682. gap: 5px;
  683. img{
  684. width: 16px;
  685. height: 16px;
  686. }
  687. }
  688. .mt-8{
  689. display: flex;
  690. align-items: center;
  691. justify-content: center;
  692. padding: 30px 0;
  693. height: 100px;
  694. }
  695. .form-table{
  696. margin-top: 10px;
  697. .btnBox{
  698. display: flex;
  699. align-items: center;
  700. margin-bottom: 12px;
  701. }
  702. :deep(.el-table .el-table__header){
  703. padding: 0;
  704. height: 30px;
  705. .el-table__cell{
  706. background: #F1F4FF;
  707. }
  708. }
  709. :deep(.el-table .el-table__cell){
  710. padding: 0;
  711. text-align: center;
  712. }
  713. :deep(.el-table__row) {
  714. height: 30px;
  715. padding: 0;
  716. &:nth-child(even) {
  717. background: #F1F4FF;
  718. }
  719. &:nth-child(odd) {
  720. background: #FFFFFF;
  721. }
  722. }
  723. .primary-btn{
  724. width: 80px;
  725. height: 30px;
  726. background: linear-gradient( 135deg, #2FB0FF 0%, #B863FB 100%);
  727. border-radius: 4px;
  728. color: #fff;
  729. font-size: 14px;
  730. text-align: center;
  731. cursor: pointer;
  732. line-height: 30px;
  733. margin-right: 10px;
  734. }
  735. .normal-btn{
  736. width: 80px;
  737. height: 30px;
  738. background: #fff;
  739. border: 1px solid #CCCCCC;
  740. border-radius: 4px;
  741. font-size: 14px;
  742. text-align: center;
  743. line-height: 30px;
  744. cursor: pointer;
  745. }
  746. .cursor-pointer{
  747. cursor: pointer;
  748. }
  749. }
  750. .editDialog{
  751. .el-dialog__body{
  752. padding: 0 !important;
  753. }
  754. .btn-row{
  755. display: flex;
  756. align-items: center;
  757. justify-content: flex-end;
  758. gap: 10px;
  759. }
  760. .primary-btn{
  761. width: 100px;
  762. height: 30px;
  763. background: linear-gradient( 135deg, #2FB0FF 0%, #B863FB 100%);
  764. border-radius: 4px;
  765. color: #fff;
  766. font-size: 14px;
  767. text-align: center;
  768. line-height: 30px;
  769. cursor: pointer;
  770. }
  771. .normal-btn{
  772. width: 100px;
  773. height: 30px;
  774. background: #fff;
  775. border: 1px solid #CCCCCC;
  776. border-radius: 4px;
  777. font-size: 14px;
  778. text-align: center;
  779. line-height: 30px;
  780. cursor: pointer;
  781. }
  782. }
  783. .config-type{
  784. font-size: 14px;
  785. color: #333333;
  786. display: flex;
  787. align-items: center;
  788. justify-content: flex-start;
  789. padding: 10px 0;
  790. .el-checkbox{
  791. margin-left: 10px;
  792. }
  793. }
  794. .editForm{
  795. display: grid;
  796. grid-template-columns: repeat(2, 1fr);
  797. gap: 0;
  798. .flex-row{
  799. display: flex;
  800. align-items: center;
  801. :deep(.el-radio){
  802. margin-right: 6px !important;
  803. }
  804. :deep(.el-radio__label){
  805. padding-left: 4px;
  806. }
  807. }
  808. :deep(.el-form-item) {
  809. margin-bottom: 0;
  810. .el-form-item__label {
  811. width: 120px !important;
  812. padding-right: 0 !important;
  813. background: #FBFCFF;
  814. border: 1px solid #EEEEEE;
  815. height: 41px;
  816. line-height: 41px;
  817. padding-left: 5px;
  818. text-align: left;
  819. }
  820. .el-form-item__content {
  821. width: 190px;
  822. position: relative;
  823. height: 41px;
  824. background: #FFFFFF;
  825. padding-left: 7px;
  826. border: 1px solid #EEEEEE;
  827. .el-input__wrapper {
  828. box-shadow: none;
  829. }
  830. .error-msg{
  831. display: none;
  832. position: absolute;
  833. top: 41px;
  834. top: 28px;
  835. left: 8px;
  836. z-index: 22;
  837. color: #dc2626;
  838. font-size: 12px;
  839. }
  840. &:hover{
  841. .error-msg{
  842. display: block;
  843. }
  844. }
  845. // 确保number类型输入框的上下箭头始终显示
  846. input[type="number"]::-webkit-inner-spin-button,
  847. input[type="number"]::-webkit-outer-spin-button {
  848. opacity: 1;
  849. height: 28px;
  850. position: absolute;
  851. top: 2px;
  852. right: 2px;
  853. cursor: pointer;
  854. }
  855. input[type="number"] {
  856. -moz-appearance: number-input; /* Firefox */
  857. }
  858. }
  859. }
  860. }
  861. </style>