index.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745
  1. <template>
  2. <headerBar
  3. >
  4. <template #title><div @click="handleSettingClick" v-log="{ describe: { action: '点击设置标题' } }">设置</div></template>
  5. </headerBar>
  6. <div class="container setting-wrap">
  7. <nav class="settings-nav">
  8. <div class="nav-item" :class="{'active': activeIndex === 0}" @click="toggleTab(0)" v-log="{ describe: { action: '点击切换设置Tab', tab: '基础配置' } }">
  9. <img src="@/assets/images/setting/icon1.png" class="nav-icon" v-if="activeIndex !== 0"/>
  10. <img src="@/assets/images/setting/icon1a.png" class="nav-icon" v-else/>
  11. <span>基础配置</span>
  12. </div>
  13. <div class="nav-item" v-if="configInfoStore.appModel === 1" :class="{'active': activeIndex === 3}" @click="toggleTab(3)" v-log="{ describe: { action: '点击切换设置Tab', tab: '相机配置' } }">
  14. <img src="@/assets/images/setting/icon2.png" class="nav-icon" v-if="activeIndex !== 3"/>
  15. <img src="@/assets/images/setting/icon2a.png" class="nav-icon" v-else/>
  16. <span>相机配置</span>
  17. </div>
  18. <div class="nav-item" :class="{'active': activeIndex === 2}" @click="toggleTab(2)" v-log="{ describe: { action: '点击切换设置Tab', tab: '其他设置' } }">
  19. <img src="@/assets/images/setting/icon3.png" class="nav-icon" v-if="activeIndex !== 2"/>
  20. <img src="@/assets/images/setting/icon3a.png" class="nav-icon" v-else/>
  21. <span>其他设置</span>
  22. </div>
  23. <div class="nav-item" v-if="configInfoStore.appModel === 1" :class="{'active': activeIndex === 4}" @click="toggleTab(4)" v-log="{ describe: { action: '点击切换设置Tab', tab: '左右脚程序设置' } }">
  24. <img src="@/assets/images/setting/icon4.png" class="nav-icon" v-if="activeIndex !== 4"/>
  25. <img src="@/assets/images/setting/icon4a.png" class="nav-icon" v-else/>
  26. <span>左右脚程序设置</span>
  27. </div>
  28. </nav>
  29. <div class="form-container">
  30. <!--基础配置-->
  31. <div class="selectBox" v-if="activeIndex === 0">
  32. <div class="form-item">
  33. <label>主图尺寸:</label>
  34. <div class="select-wrapper">
  35. <el-select multiple
  36. collapse-tags
  37. multiple-limit="3"
  38. v-model="formData.basic_configs.main_image_size" placeholder="请选择">
  39. <el-option v-for="item in mainImageSizeList" :key="item.value" :label="item.label" :value="item.value"></el-option>
  40. </el-select>
  41. </div>
  42. </div>
  43. <!-- 新增自定义输入框 -->
  44. <div class="form-item" v-if="formData.basic_configs.main_image_size.includes('custom')">
  45. <label>自定义尺寸:</label>
  46. <div class="select-wrapper">
  47. <el-input
  48. type="text"
  49. v-model.number="customInput"
  50. maxlength="4"
  51. placeholder="请输入1-2000的尺寸值"
  52. class="w-full px-3 py-2 border rounded-md"
  53. @keypress="handleKeyPress"
  54. @input="handleInput"
  55. />
  56. </div>
  57. </div>
  58. <div class="form-item">
  59. <label>图片输出格式:</label>
  60. <div class="select-wrapper">
  61. <el-select v-model="formData.basic_configs.image_out_format" placeholder="请选择">
  62. <el-option v-for="item in imageFormatList" :key="item.value" :label="item.label" :value="item.value"></el-option>
  63. </el-select>
  64. </div>
  65. </div>
  66. <div class="form-item">
  67. <label>图片锐化:</label>
  68. <div class="select-wrapper">
  69. <el-select v-model="formData.basic_configs.image_sharpening" placeholder="请选择">
  70. <el-option v-for="item in imageSharpeningList" :key="item.value" :label="item.label" :value="item.value"></el-option>
  71. </el-select>
  72. </div>
  73. </div>
  74. <DebugPanel ref="debugPanel" />
  75. </div>
  76. <!--基础配置-->
  77. <!--相机配置-->
  78. <template v-if="activeIndex === 3">
  79. <CameraConfig ref="cameraConfigRef" :camera_configs="formData.camera_configs" @update:camera_configs="updateCameraConfigs"/>
  80. </template>
  81. <!--相机配置-->
  82. <!--其他设置-->
  83. <template v-if="activeIndex === 2">
  84. <div class="selectBox" style="padding-top: 0px" >
  85. <div class="form-item">
  86. <label>产品类型:</label>
  87. <div class="select-wrapper">
  88. <el-select v-model="formData.other_configs.product_type" placeholder="请选择">
  89. <el-option v-for="item in productTypeList" :key="item.value" :label="item.label" :value="item.value"></el-option>
  90. </el-select>
  91. </div>
  92. </div>
  93. <div class="form-item">
  94. <label>默认抠图模式:</label>
  95. <div class="select-wrapper">
  96. <el-select v-model="formData.other_configs.cutout_mode" placeholder="请选择">
  97. <el-option v-for="item in defaultCutoutModeList" :key="item.value" :label="item.label" :value="item.value"></el-option>
  98. </el-select>
  99. </div>
  100. </div>
  101. <div class="form-item">
  102. <label>设备运动速度:</label>
  103. <div class="select-wrapper">
  104. <el-select v-model="formData.other_configs.device_speed" placeholder="请选择">
  105. <el-option v-for="item in deviceSpeedList" :key="item.value" :label="item.label" :value="item.value"></el-option>
  106. </el-select>
  107. </div>
  108. </div>
  109. <other-config/>
  110. <!-- <div class="form-item">
  111. <label>运行模式:</label>
  112. <div class="select-wrapper">
  113. <el-select v-model="formData.other_configs.running_mode" placeholder="请选择">
  114. <el-option v-for="item in runModeList" :key="item.value" :label="item.label" :value="item.value"></el-option>
  115. </el-select>
  116. </div>
  117. </div>-->
  118. </div>
  119. </template>
  120. <!--其他设置-->
  121. <div class="selectBox" style="padding-top: 0px;padding-left: 0;" v-if="activeIndex === 4">
  122. <actionConfig/>
  123. </div>
  124. </div>
  125. <div class="text-center mt-8">
  126. <button class="bg-gradient-to-r from-primary" @click="onSava(activeIndex)" v-if="activeIndex !== 4" v-log="{ describe: { action: '点击保存设置', tabIndex: activeIndex } }">
  127. 保存
  128. </button>
  129. </div>
  130. </div>
  131. </template>
  132. <script setup>
  133. /**
  134. * Vue组件逻辑部分,包含与设备配置相关的功能。
  135. * 主要功能包括:表单数据管理、设备配置列表获取、新增/编辑/删除步骤、保存配置等。
  136. */
  137. // 引入Vue相关功能和第三方库
  138. import { ref, reactive } from 'vue';
  139. import { useRoute, useRouter } from 'vue-router';
  140. import { onMounted, watch } from 'vue';
  141. import { getAllUserConfigs, setAllUserConfigs } from '@/apis/setting'
  142. import socket from "@/stores/modules/socket";
  143. import headerBar from '@/components/header-bar/index.vue';
  144. import client from "@/stores/modules/client";
  145. import icpList from '@/utils/ipc';
  146. const clientStore = client();
  147. import { ElMessage, ElMessageBox } from 'element-plus';
  148. import { digiCamControlWEB } from '@/utils/appconfig'
  149. import { useCheckInfo } from '@/composables/userCheck';
  150. import { preview } from '@planckdev/element-plus/utils'
  151. import actionConfig from './components/action_config.vue'
  152. import otherConfig from './components/otherConfig'
  153. import CameraConfig from './components/CameraConfig';
  154. useCheckInfo();
  155. //点击三次 打开资源目录
  156. import DebugPanel from './components/DebugPanel.vue';
  157. // 在setup函数中创建调试面板实例
  158. const debugPanel = ref(null);
  159. const cameraConfigRef = ref(null);
  160. // 添加设置点击计数器
  161. const settingClickCount = ref(0);
  162. // 修改headerBar的点击处理函数
  163. function handleSettingClick() {
  164. console.log('handleSettingClickhandleSettingClick')
  165. settingClickCount.value++;
  166. if (settingClickCount.value >= 3) {
  167. if (debugPanel.value) {
  168. debugPanel.value.showDebugPanel();
  169. }
  170. settingClickCount.value = 0;
  171. }
  172. setTimeout(() => {
  173. settingClickCount.value = 0;
  174. }, 3000); // 3秒内未再次点击则重置计数器
  175. }
  176. // 路由和状态管理初始化
  177. const route = useRoute();
  178. const router = useRouter();
  179. // 定义响应式变量
  180. const folderPath = ref(''); // 文件夹路径
  181. const activeIndex = ref(0); // 当前激活的索引
  182. const socketStore = socket(); // WebSocket状态管理实例
  183. import configInfo from '@/stores/modules/config';
  184. const configInfoStore = configInfo();
  185. /**
  186. * 表单数据对象,用于存储设备配置信息。
  187. */
  188. const formData = reactive({
  189. //基础配置
  190. basic_configs:{
  191. "main_image_size": [],//主图尺寸
  192. "image_out_format": "",//图片输出格式
  193. "image_sharpening": "" //图片锐化
  194. },
  195. //拍照配置
  196. take_photo_configs:{
  197. "repart_take_photo_warning": false,//重复拍摄警告
  198. "single_photo_warning": "",//单次张数警告
  199. "total_photo_warning": "",//累计拍照警告
  200. "camera_delay": ""//拍照停留
  201. },
  202. other_configs:{
  203. "product_type": "",//产品类型
  204. "cutout_mode": "",//默认抠图模式
  205. "device_speed": "",//设备运动速度
  206. "running_mode": "" //运行模式
  207. },
  208. /* captureOneFolder: '', // Capture One文件夹路径
  209. mainImageSize: '', // 主图尺寸
  210. imageFormat: '', // 图片格式
  211. imageSharpening: '', // 图片锐化
  212. repeatWarning: '', // 重复警告
  213. singleWarning: '', // 单次警告
  214. totalWarning: '', // 总警告
  215. focusTime: '', // 对焦时间
  216. photoTime: '', // 拍照时间
  217. productType: '', // 产品类型
  218. defaultCutoutMode: '', // 默认抠图模式
  219. deviceSpeed: '', // 设备速度
  220. runMode: '', // 运行模式
  221. receiver: '', // 接收器类型
  222. left: '', // 左脚配置
  223. right: '', // 右脚配置
  224. up: '', // 上移配置
  225. down: '', // 下移配置*/
  226. });
  227. // 配置选项列表
  228. const mainImageSizeList = ref([
  229. { label: '320*320', value: 320 },
  230. { label: '512*512', value: 512 },
  231. { label: '768*768', value: 768 },
  232. { label: '800*800', value: 800 },
  233. { label: '1024*1024', value: 1024 },
  234. { label: '1200*1200', value: 1200 },
  235. { label: '1400*1400', value: 1400 },
  236. { label: '1600*1600', value: 1600 },
  237. { label: '自定义', value: 'custom' } // 新增自定义选项
  238. ]);
  239. const customInput = ref(null); // 新增自定义输入值
  240. const imageFormatList = ref([
  241. { label: 'jpg', value: 'jpg' },
  242. { label: 'png', value: 'png' },
  243. { label: 'jpeg', value: 'jpeg' },
  244. { label: 'webp', value: 'webp' },
  245. { label: 'avif', value: 'avif' },
  246. ]);
  247. const imageSharpeningList = ref([
  248. { label: '0', value: '0' },
  249. { label: '1', value: '1' },
  250. { label: '2', value: '2' },
  251. { label: '3', value: '3' },
  252. ]);
  253. const repeatWarningList = ref([
  254. { label: '关闭', value: false },
  255. { label: '开启', value: true },
  256. ]);
  257. const singleWarningList = ref([
  258. { label: '11', value: '11' },
  259. { label: '12', value: '12' },
  260. { label: '13', value: '13' },
  261. ]);
  262. const totalWarningList = ref([
  263. { label: '1.0', value: '1.0' },
  264. { label: '1.5', value: '1.5' },
  265. { label: '2.0', value: '2.0' },
  266. ]);
  267. const productTypeList = ref([
  268. { label: '鞋类', value: '鞋类' },
  269. { label: '服装', value: '服装' },
  270. { label: '箱包', value: '箱包' },
  271. ]);
  272. const defaultCutoutModeList = ref([
  273. { label: '普通抠图', value: '普通抠图' },
  274. { label: '精细化抠图', value: '精细化抠图' },
  275. ]);
  276. const deviceSpeedList = ref([
  277. { label: '一档', value: '一档' },
  278. { label: '二档', value: '二档' },
  279. { label: '三档', value: '三档' },
  280. ]);
  281. /*
  282. const runModeList = ref([
  283. { label: '普通模式', value: '普通模式' },
  284. { label: '待用户确认模式', value: '待用户确认模式' }
  285. ]);
  286. const receiverList = ref([
  287. { label: '蓝牙', value: '1' },
  288. { label: '2.4G', value: '2' },
  289. { label: '5.8G', value: '3' },
  290. ]);
  291. const leftList = ref([
  292. { label: '左脚', value: '1' },
  293. { label: '右脚', value: '2' },
  294. { label: '左右脚', value: '3' },
  295. ]);
  296. const rightList = ref([
  297. { label: '左脚', value: '1' },
  298. { label: '右脚', value: '2' },
  299. { label: '左右脚', value: '3' },
  300. ]);
  301. const upList = ref([
  302. { label: '上移', value: '1' },
  303. { label: '下移', value: '2' },
  304. { label: '左右移', value: '3' },
  305. ]);
  306. const downList = ref([
  307. { label: '上移', value: '1' },
  308. { label: '下移', value: '2' },
  309. { label: '左右移', value: '3' },
  310. ]);
  311. */
  312. const indexKey ={
  313. 0:"basic_configs",
  314. 1:"take_photo_configs",
  315. 2:"other_configs",
  316. }
  317. /**
  318. * 监听路由参数变化,更新activeIndex和activeTab。
  319. */
  320. watch(() => route.query.type, async (newType,oldType) => {
  321. const typeValue = parseInt(newType) || 0;
  322. getConfig()
  323. });
  324. /**
  325. * 监听activeIndex变化,更新URL中的查询参数。
  326. */
  327. watch(() => activeIndex.value, (newIndex) => {
  328. router.push({
  329. query: {
  330. ...route.query,
  331. type: newIndex.toString()
  332. }
  333. });
  334. });
  335. const getConfig = async (typeValue)=>{
  336. const resultPHP = await getAllUserConfigs();
  337. if(resultPHP.code == 0 && resultPHP.data.configs ){
  338. Object.keys(resultPHP.data.configs).map(item=>{
  339. formData[item] = resultPHP.data.configs[item]
  340. })
  341. console.log(formData);
  342. const presetSizes = mainImageSizeList.value.map(item => item.value);
  343. const receivedSizes = formData.basic_configs.main_image_size ? [...formData.basic_configs.main_image_size] : [];
  344. // 分离自定义值
  345. const customValues = receivedSizes.filter(v => !presetSizes.includes(v));
  346. if (customValues.length > 0) {
  347. customInput.value = customValues[0]; // 保留第一个自定义值
  348. // 更新选中状态
  349. formData.basic_configs.main_image_size = receivedSizes
  350. .filter(v => presetSizes.includes(v))
  351. .concat('custom');
  352. } else {
  353. formData.basic_configs.main_image_size = receivedSizes;
  354. }
  355. }
  356. }
  357. /**
  358. * 组件挂载时初始化activeIndex。
  359. */
  360. onMounted(async () => {
  361. getConfig()
  362. let type = 0 ;
  363. if (route.query.type) {
  364. const typeValue = parseInt(route.query.type);
  365. type = typeValue
  366. if (!isNaN(typeValue) && typeValue >= 0 && typeValue <= 3) {
  367. activeIndex.value = typeValue;
  368. }
  369. }
  370. });
  371. const handleKeyPress = (event) => {
  372. const char = event.key;
  373. // 只允许输入数字字符
  374. if (!/^\d+$/.test(char)) {
  375. event.preventDefault(); // 阻止非数字输入
  376. }
  377. };
  378. const handleInput = (value) => {
  379. if (value > 2000) {
  380. customInput.value = 2000;
  381. } else if (value < 1) {
  382. customInput.value = 1;
  383. }
  384. };
  385. // 添加更新camera_configs的方法
  386. const updateCameraConfigs = (configs) => {
  387. formData.camera_configs = configs;
  388. };
  389. const toggleTab = async (item) => {
  390. const oldType = activeIndex.value;
  391. // 切换前保存当前 Tab 配置(包含相机配置 3)
  392. if ([0,1,2,3].includes(oldType)) {
  393. const next = await saveSetting(oldType);
  394. if (next === false) return false;
  395. }
  396. activeIndex.value = item;
  397. return true;
  398. };
  399. const onSava = async (index)=>{
  400. const next = await saveSetting(index)
  401. if(next !== false){
  402. ElMessage.success('保存成功')
  403. }
  404. }
  405. /**
  406. * 保存当前表单配置。
  407. */
  408. const saveSetting = async (index) => {
  409. // 构建临时提交数据
  410. if(index === 3) {
  411. if (cameraConfigRef.value && typeof cameraConfigRef.value.save === 'function') {
  412. if(! cameraConfigRef.value.save()) return false;
  413. }
  414. }
  415. const submitData = {
  416. ...formData
  417. };
  418. if(index === 0) {
  419. if (formData.basic_configs.main_image_size.length === 0) {
  420. ElMessage.error('请选择主图尺寸!');
  421. return false;
  422. }
  423. // 处理自定义尺寸逻辑
  424. const selectedSizes = [...formData.basic_configs.main_image_size]; // 创建副本避免修改原始数据
  425. if (selectedSizes.includes('custom')) {
  426. if (!customInput.value || isNaN(customInput.value) ||
  427. customInput.value < 1 || customInput.value > 2000) {
  428. ElMessage.error('请输入1-2000之间的有效数值');
  429. return false;
  430. }
  431. // 创建新数组用于提交
  432. const submitSizes = selectedSizes
  433. .filter(v => v !== 'custom')
  434. .concat(parseInt(customInput.value));
  435. submitData.main_image_size = submitSizes
  436. }
  437. }
  438. const params = JSON.parse(JSON.stringify({
  439. configs:submitData
  440. }))
  441. const result = await setAllUserConfigs(params)
  442. if(result.code != 0) return false;
  443. return true;
  444. };
  445. </script>
  446. <style lang="scss">
  447. .el-image-viewer__wrapper{
  448. z-index: 9999 !important;
  449. }
  450. .setting-wrap {
  451. .selectBox{
  452. padding-top: 30px;
  453. padding-left: 100px;
  454. border-bottom: 1px solid rgba(0,0,0,0.1);
  455. ::v-deep(.el-tabs__header){
  456. padding-left: 0;
  457. }
  458. ::v-deep(.el-tabs--card>.el-tabs__header){
  459. border-bottom: 1px solid #CCCCCC;
  460. }
  461. ::v-deep(.el-tabs__item){
  462. height: 30px;
  463. line-height: 30px;
  464. }
  465. ::v-deep(.el-tabs__nav-wrap){
  466. margin-bottom: 0;
  467. }
  468. ::v-deep(.el-tabs__item.is-active){
  469. color: #333;
  470. font-weight: bold;
  471. background: #fff;
  472. }
  473. }
  474. .form-item {
  475. margin-bottom: 24px;
  476. display: flex;
  477. align-items: center;
  478. }
  479. .form-item label {
  480. display: block;
  481. min-width: 98px;
  482. text-align: right;
  483. font-size: 14px;
  484. color: #1A1A1A;
  485. }
  486. .select-wrapper {
  487. position: relative;
  488. width: 200px;
  489. ::v-deep(.el-input__inner){
  490. border-radius: 6px;
  491. }
  492. }
  493. }
  494. </style>
  495. <style lang="scss" scoped>
  496. body {
  497. background: #EAECED;
  498. }
  499. .container {
  500. margin: 0 auto;
  501. min-height: calc(100vh - 30px);
  502. background: #EAECED;
  503. display: flex;
  504. flex-direction: column;
  505. justify-content: flex-start;
  506. }
  507. .settings-nav {
  508. display: flex;
  509. justify-content: center;
  510. gap: 40px;
  511. padding: 30px 0;
  512. background: #EDEFF0;
  513. border-bottom: 1px solid rgba(0,0,0,0.1);
  514. }
  515. .nav-item {
  516. display: flex;
  517. flex-direction: column;
  518. align-items: center;
  519. cursor: pointer;
  520. color: #666;
  521. transition: all 0.3s;
  522. width: 100px;
  523. justify-content: center;
  524. height: 70px;
  525. font-size: 14px;
  526. }
  527. .nav-item.active {
  528. background: #DFE2E3;
  529. border-radius: 10px;
  530. color: #2957FF;
  531. }
  532. .nav-item i {
  533. font-size: 24px;
  534. margin-bottom: 8px;
  535. width: 40px;
  536. height: 40px;
  537. display: flex;
  538. justify-content: center;
  539. align-items: center;
  540. background: #fff;
  541. border-radius: 8px;
  542. }
  543. .form-container {
  544. border-radius: 12px;
  545. padding: 30px;
  546. padding-top: 10px;
  547. width: 800px;
  548. margin: 0 auto;
  549. height: 306px;
  550. }
  551. .input-group {
  552. display: flex;
  553. gap: 12px;
  554. }
  555. .input-group input {
  556. flex: 1;
  557. border: 1px solid #e5e7eb;
  558. border-radius: 4px;
  559. padding: 8px 12px;
  560. font-size: 14px;
  561. }
  562. .error-text {
  563. color: #dc2626;
  564. font-size: 12px;
  565. margin-top: 4px;
  566. }
  567. .from-primary{
  568. width: 150px;
  569. height: 40px;
  570. color: #FFFFFF;
  571. background: linear-gradient( 135deg, #2FB0FF 0%, #B863FB 100%);
  572. }
  573. .nav-icon{
  574. width: 32px;
  575. height: 32px;
  576. }
  577. .captureBox{
  578. border-bottom: 1px solid rgba(0,0,0,0.1);
  579. }
  580. .select-btn{
  581. display: flex;
  582. align-items: center;
  583. flex-shrink: 0;
  584. width: 120px;
  585. height: 30px;
  586. background: #DFE2E3;
  587. border-radius: 6px;
  588. justify-content: center;
  589. font-size: 14px;
  590. color: #2957FF;
  591. gap: 5px;
  592. img{
  593. width: 16px;
  594. height: 16px;
  595. }
  596. }
  597. .mt-8{
  598. display: flex;
  599. align-items: center;
  600. justify-content: center;
  601. padding: 30px 0;
  602. height: 100px;
  603. }
  604. .config-type{
  605. font-size: 14px;
  606. color: #333333;
  607. display: flex;
  608. align-items: center;
  609. justify-content: flex-start;
  610. padding: 10px 0;
  611. .el-checkbox{
  612. margin-left: 10px;
  613. }
  614. }
  615. .editForm{
  616. display: grid;
  617. grid-template-columns: repeat(2, 1fr);
  618. gap: 0;
  619. .flex-row{
  620. display: flex;
  621. align-items: center;
  622. ::v-deep(.el-radio){
  623. margin-right: 6px !important;
  624. }
  625. ::v-deep(.el-radio__label){
  626. padding-left: 4px;
  627. }
  628. }
  629. ::v-deep(.el-form-item) {
  630. margin-bottom: 0;
  631. .el-form-item__label {
  632. width: 120px !important;
  633. padding-right: 0 !important;
  634. background: #FBFCFF;
  635. border: 1px solid #EEEEEE;
  636. height: 41px;
  637. line-height: 41px;
  638. padding-left: 5px;
  639. text-align: left;
  640. }
  641. .el-form-item__content {
  642. width: 190px;
  643. position: relative;
  644. height: 41px;
  645. background: #FFFFFF;
  646. padding-left: 7px;
  647. border: 1px solid #EEEEEE;
  648. .el-input__wrapper {
  649. box-shadow: none;
  650. }
  651. .error-msg{
  652. display: none;
  653. position: absolute;
  654. top: 41px;
  655. top: 28px;
  656. left: 8px;
  657. z-index: 22;
  658. color: #dc2626;
  659. font-size: 12px;
  660. }
  661. &:hover{
  662. .error-msg{
  663. display: block;
  664. }
  665. }
  666. // 确保number类型输入框的上下箭头始终显示
  667. input[type="number"]::-webkit-inner-spin-button,
  668. input[type="number"]::-webkit-outer-spin-button {
  669. opacity: 1;
  670. height: 28px;
  671. position: absolute;
  672. top: 2px;
  673. right: 2px;
  674. cursor: pointer;
  675. }
  676. input[type="number"] {
  677. -moz-appearance: textfield; /* Firefox */
  678. }
  679. }
  680. }
  681. }
  682. </style>