index.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  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" v-if="configInfoStore.appModel === 1" :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 multiple
  30. collapse-tags
  31. multiple-limit="3"
  32. v-model="formData.basic_configs.main_image_size" placeholder="请选择">
  33. <el-option v-for="item in mainImageSizeList" :key="item.value" :label="item.label" :value="item.value"></el-option>
  34. </el-select>
  35. </div>
  36. </div>
  37. <div class="form-item">
  38. <label>图片输出格式:</label>
  39. <div class="select-wrapper">
  40. <el-select v-model="formData.basic_configs.image_out_format" placeholder="请选择">
  41. <el-option v-for="item in imageFormatList" :key="item.value" :label="item.label" :value="item.value"></el-option>
  42. </el-select>
  43. </div>
  44. </div>
  45. <div class="form-item">
  46. <label>图片锐化:</label>
  47. <div class="select-wrapper">
  48. <el-select v-model="formData.basic_configs.image_sharpening" placeholder="请选择">
  49. <el-option v-for="item in imageSharpeningList" :key="item.value" :label="item.label" :value="item.value"></el-option>
  50. </el-select>
  51. </div>
  52. </div>
  53. </div>
  54. <!--基础配置-->
  55. <!--其他设置-->
  56. <template v-if="activeIndex === 2">
  57. <div class="selectBox" style="padding-top: 0px" >
  58. <div class="form-item">
  59. <label>产品类型:</label>
  60. <div class="select-wrapper">
  61. <el-select v-model="formData.other_configs.product_type" placeholder="请选择">
  62. <el-option v-for="item in productTypeList" :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.other_configs.cutout_mode" placeholder="请选择">
  70. <el-option v-for="item in defaultCutoutModeList" :key="item.value" :label="item.label" :value="item.value"></el-option>
  71. </el-select>
  72. </div>
  73. </div>
  74. <div class="form-item">
  75. <label>设备运动速度:</label>
  76. <div class="select-wrapper">
  77. <el-select v-model="formData.other_configs.device_speed" placeholder="请选择">
  78. <el-option v-for="item in deviceSpeedList" :key="item.value" :label="item.label" :value="item.value"></el-option>
  79. </el-select>
  80. </div>
  81. </div>
  82. <!-- <div class="form-item">
  83. <label>运行模式:</label>
  84. <div class="select-wrapper">
  85. <el-select v-model="formData.other_configs.running_mode" placeholder="请选择">
  86. <el-option v-for="item in runModeList" :key="item.value" :label="item.label" :value="item.value"></el-option>
  87. </el-select>
  88. </div>
  89. </div>-->
  90. </div>
  91. <other-config/>
  92. </template>
  93. <!--其他设置-->
  94. <div class="selectBox" style="padding-top: 0px;padding-left: 0;" v-if="activeIndex === 4">
  95. <actionConfig/>
  96. </div>
  97. </div>
  98. <div class="text-center mt-8">
  99. <button class="bg-gradient-to-r from-primary" @click="saveSetting(activeIndex)" v-if="activeIndex !== 4">
  100. 保存
  101. </button>
  102. </div>
  103. </div>
  104. </template>
  105. <script setup>
  106. /**
  107. * Vue组件逻辑部分,包含与设备配置相关的功能。
  108. * 主要功能包括:表单数据管理、设备配置列表获取、新增/编辑/删除步骤、保存配置等。
  109. */
  110. // 引入Vue相关功能和第三方库
  111. import { ref, reactive } from 'vue';
  112. import { useRoute, useRouter } from 'vue-router';
  113. import { onMounted, watch } from 'vue';
  114. import socket from "@/stores/modules/socket";
  115. import headerBar from '@/components/header-bar/index.vue';
  116. import client from "@/stores/modules/client";
  117. import icpList from '@/utils/ipc';
  118. const clientStore = client();
  119. import { ElMessage, ElMessageBox } from 'element-plus';
  120. import { digiCamControlWEB } from '@/utils/appconfig'
  121. import { useCheckInfo } from '@/composables/userCheck';
  122. import { preview } from '@planckdev/element-plus/utils'
  123. import actionConfig from './components/action_config.vue'
  124. import otherConfig from './components/otherConfig'
  125. useCheckInfo();
  126. // 路由和状态管理初始化
  127. const route = useRoute();
  128. const router = useRouter();
  129. // 定义响应式变量
  130. const folderPath = ref(''); // 文件夹路径
  131. const activeIndex = ref(0); // 当前激活的索引
  132. const socketStore = socket(); // WebSocket状态管理实例
  133. import configInfo from '@/stores/modules/config';
  134. const configInfoStore = configInfo();
  135. /**
  136. * 表单数据对象,用于存储设备配置信息。
  137. */
  138. const formData = reactive({
  139. //基础配置
  140. basic_configs:{
  141. "main_image_size": [],//主图尺寸
  142. "image_out_format": "",//图片输出格式
  143. "image_sharpening": "" //图片锐化
  144. },
  145. //拍照配置
  146. take_photo_configs:{
  147. "repart_take_photo_warning": false,//重复拍摄警告
  148. "single_photo_warning": "",//单次张数警告
  149. "total_photo_warning": "",//累计拍照警告
  150. "camera_delay": ""//拍照停留
  151. },
  152. other_configs:{
  153. "product_type": "",//产品类型
  154. "cutout_mode": "",//默认抠图模式
  155. "device_speed": "",//设备运动速度
  156. "running_mode": "" //运行模式
  157. },
  158. captureOneFolder: '', // Capture One文件夹路径
  159. mainImageSize: '', // 主图尺寸
  160. imageFormat: '', // 图片格式
  161. imageSharpening: '', // 图片锐化
  162. repeatWarning: '', // 重复警告
  163. singleWarning: '', // 单次警告
  164. totalWarning: '', // 总警告
  165. focusTime: '', // 对焦时间
  166. photoTime: '', // 拍照时间
  167. productType: '', // 产品类型
  168. defaultCutoutMode: '', // 默认抠图模式
  169. deviceSpeed: '', // 设备速度
  170. runMode: '', // 运行模式
  171. receiver: '', // 接收器类型
  172. left: '', // 左脚配置
  173. right: '', // 右脚配置
  174. up: '', // 上移配置
  175. down: '', // 下移配置
  176. });
  177. // 配置选项列表
  178. const mainImageSizeList = ref([
  179. { label: '320*320', value: 320 },
  180. { label: '512*512', value: 512 },
  181. { label: '768*768', value: 768 },
  182. { label: '800*800', value: 800 },
  183. { label: '1024*1024', value: 1024 },
  184. { label: '1200*1200', value: 1200 },
  185. { label: '1400*1400', value: 1400 },
  186. { label: '1600*1600', value: 1600 },
  187. ]);
  188. const imageFormatList = ref([
  189. { label: 'jpg', value: 'jpg' },
  190. { label: 'png', value: 'png' },
  191. { label: 'jpeg', value: 'jpeg' },
  192. { label: 'webp', value: 'webp' },
  193. { label: 'avif', value: 'avif' },
  194. ]);
  195. const imageSharpeningList = ref([
  196. { label: '0', value: '0' },
  197. { label: '1', value: '1' },
  198. { label: '2', value: '2' },
  199. { label: '3', value: '3' },
  200. ]);
  201. const repeatWarningList = ref([
  202. { label: '关闭', value: false },
  203. { label: '开启', value: true },
  204. ]);
  205. const singleWarningList = ref([
  206. { label: '11', value: '11' },
  207. { label: '12', value: '12' },
  208. { label: '13', value: '13' },
  209. ]);
  210. const totalWarningList = ref([
  211. { label: '1.0', value: '1.0' },
  212. { label: '1.5', value: '1.5' },
  213. { label: '2.0', value: '2.0' },
  214. ]);
  215. const productTypeList = ref([
  216. { label: '鞋类', value: '鞋类' },
  217. { label: '服装', value: '服装' },
  218. { label: '箱包', value: '箱包' },
  219. ]);
  220. const defaultCutoutModeList = ref([
  221. { label: '普通抠图', value: '普通抠图' },
  222. { label: '精细化抠图', value: '精细化抠图' },
  223. ]);
  224. const deviceSpeedList = ref([
  225. { label: '一档', value: '1' },
  226. { label: '二档', value: '2' },
  227. { label: '三档', value: '3' },
  228. ]);
  229. /*
  230. const runModeList = ref([
  231. { label: '普通模式', value: '普通模式' },
  232. { label: '待用户确认模式', value: '待用户确认模式' }
  233. ]);
  234. const receiverList = ref([
  235. { label: '蓝牙', value: '1' },
  236. { label: '2.4G', value: '2' },
  237. { label: '5.8G', value: '3' },
  238. ]);
  239. const leftList = ref([
  240. { label: '左脚', value: '1' },
  241. { label: '右脚', value: '2' },
  242. { label: '左右脚', value: '3' },
  243. ]);
  244. const rightList = ref([
  245. { label: '左脚', value: '1' },
  246. { label: '右脚', value: '2' },
  247. { label: '左右脚', value: '3' },
  248. ]);
  249. const upList = ref([
  250. { label: '上移', value: '1' },
  251. { label: '下移', value: '2' },
  252. { label: '左右移', value: '3' },
  253. ]);
  254. const downList = ref([
  255. { label: '上移', value: '1' },
  256. { label: '下移', value: '2' },
  257. { label: '左右移', value: '3' },
  258. ]);
  259. */
  260. const indexKey ={
  261. 0:"basic_configs",
  262. 1:"take_photo_configs",
  263. 2:"other_configs",
  264. }
  265. /**
  266. * 监听路由参数变化,更新activeIndex和activeTab。
  267. */
  268. watch(() => route.query.type, async (newType,oldType) => {
  269. if(['0','1','2'].includes(oldType)){
  270. await saveSetting(oldType)
  271. }
  272. const typeValue = parseInt(newType) || 0;
  273. if(typeValue === 4) return;
  274. switch (typeValue) {
  275. default:
  276. clientStore.ipc.removeAllListeners(icpList.setting.getSysConfig);
  277. clientStore.ipc.send(icpList.setting.getSysConfig,{
  278. key: indexKey[typeValue]
  279. });
  280. clientStore.ipc.on(icpList.setting.getSysConfig, (event, result) => {
  281. if(result.code == 0 && result.data){
  282. formData[indexKey[typeValue]] = result.data
  283. }
  284. console.log('icpList.setting.getSysConfig')
  285. console.log(result)
  286. clientStore.ipc.removeAllListeners(icpList.setting.getSysConfig);
  287. });
  288. break;
  289. }
  290. }, { immediate: true });
  291. /**
  292. * 监听activeIndex变化,更新URL中的查询参数。
  293. */
  294. watch(() => activeIndex.value, (newIndex) => {
  295. router.push({
  296. query: {
  297. ...route.query,
  298. type: newIndex.toString()
  299. }
  300. });
  301. });
  302. /**
  303. * 组件挂载时初始化activeIndex。
  304. */
  305. onMounted(() => {
  306. if (route.query.type) {
  307. const typeValue = parseInt(route.query.type);
  308. if (!isNaN(typeValue) && typeValue >= 0 && typeValue <= 3) {
  309. activeIndex.value = typeValue;
  310. }
  311. }
  312. });
  313. /**
  314. * 保存当前表单配置。
  315. */
  316. const saveSetting = async (index) => {
  317. if(index === 0){
  318. if(formData.basic_configs.main_image_size.length === 0){
  319. ElMessage.error('请选择主图尺寸!');
  320. return;
  321. }
  322. }
  323. await new Promise((resolve, reject) => {
  324. clientStore.ipc.removeAllListeners(icpList.setting.updateSysConfigs);
  325. clientStore.ipc.send(icpList.setting.updateSysConfigs,{
  326. key: indexKey[index],
  327. value:JSON.stringify({
  328. ...formData[indexKey[index]]
  329. })
  330. });
  331. clientStore.ipc.on(icpList.setting.updateSysConfigs, async (event, result) => {
  332. clientStore.ipc.removeAllListeners(icpList.setting.updateSysConfigs);
  333. if(result.code === 0 && result.msg){
  334. resolve(result)
  335. }
  336. });
  337. });
  338. };
  339. </script>
  340. <style lang="scss">
  341. .el-image-viewer__wrapper{
  342. z-index: 9999 !important;
  343. }
  344. </style>
  345. <style lang="scss" scoped>
  346. body {
  347. background: #EAECED;
  348. }
  349. .container {
  350. margin: 0 auto;
  351. min-height: calc(100vh - 30px);
  352. background: #EAECED;
  353. display: flex;
  354. flex-direction: column;
  355. justify-content: flex-start;
  356. }
  357. .settings-nav {
  358. display: flex;
  359. justify-content: center;
  360. gap: 40px;
  361. padding: 30px 0;
  362. background: #EDEFF0;
  363. border-bottom: 1px solid rgba(0,0,0,0.1);
  364. }
  365. .nav-item {
  366. display: flex;
  367. flex-direction: column;
  368. align-items: center;
  369. cursor: pointer;
  370. color: #666;
  371. transition: all 0.3s;
  372. width: 100px;
  373. justify-content: center;
  374. height: 70px;
  375. font-size: 14px;
  376. }
  377. .nav-item.active {
  378. background: #DFE2E3;
  379. border-radius: 10px;
  380. color: #2957FF;
  381. }
  382. .nav-item i {
  383. font-size: 24px;
  384. margin-bottom: 8px;
  385. width: 40px;
  386. height: 40px;
  387. display: flex;
  388. justify-content: center;
  389. align-items: center;
  390. background: #fff;
  391. border-radius: 8px;
  392. }
  393. .form-container {
  394. border-radius: 12px;
  395. padding: 30px;
  396. padding-top: 10px;
  397. width: 800px;
  398. margin: 0 auto;
  399. height: 306px;
  400. }
  401. .form-item {
  402. margin-bottom: 24px;
  403. display: flex;
  404. align-items: center;
  405. }
  406. .form-item label {
  407. display: block;
  408. min-width: 98px;
  409. text-align: right;
  410. font-size: 14px;
  411. color: #1A1A1A;
  412. }
  413. .input-group {
  414. display: flex;
  415. gap: 12px;
  416. }
  417. .input-group input {
  418. flex: 1;
  419. border: 1px solid #e5e7eb;
  420. border-radius: 4px;
  421. padding: 8px 12px;
  422. font-size: 14px;
  423. }
  424. .select-wrapper {
  425. position: relative;
  426. width: 200px;
  427. :deep(.el-input__inner){
  428. border-radius: 6px;
  429. }
  430. }
  431. .error-text {
  432. color: #dc2626;
  433. font-size: 12px;
  434. margin-top: 4px;
  435. }
  436. .from-primary{
  437. width: 150px;
  438. height: 40px;
  439. color: #FFFFFF;
  440. background: linear-gradient( 135deg, #2FB0FF 0%, #B863FB 100%);
  441. }
  442. .nav-icon{
  443. width: 32px;
  444. height: 32px;
  445. }
  446. .captureBox{
  447. border-bottom: 1px solid rgba(0,0,0,0.1);
  448. }
  449. .selectBox{
  450. padding-top: 30px;
  451. padding-left: 100px;
  452. border-bottom: 1px solid rgba(0,0,0,0.1);
  453. :deep(.el-tabs__header){
  454. padding-left: 0;
  455. }
  456. :deep(.el-tabs--card>.el-tabs__header){
  457. border-bottom: 1px solid #CCCCCC;
  458. }
  459. :deep(.el-tabs__item){
  460. height: 30px;
  461. line-height: 30px;
  462. }
  463. :deep(.el-tabs__nav-wrap){
  464. margin-bottom: 0;
  465. }
  466. :deep(.el-tabs__item.is-active){
  467. color: #333;
  468. font-weight: bold;
  469. background: #fff;
  470. }
  471. }
  472. .select-btn{
  473. display: flex;
  474. align-items: center;
  475. flex-shrink: 0;
  476. width: 120px;
  477. height: 30px;
  478. background: #DFE2E3;
  479. border-radius: 6px;
  480. justify-content: center;
  481. font-size: 14px;
  482. color: #2957FF;
  483. gap: 5px;
  484. img{
  485. width: 16px;
  486. height: 16px;
  487. }
  488. }
  489. .mt-8{
  490. display: flex;
  491. align-items: center;
  492. justify-content: center;
  493. padding: 30px 0;
  494. height: 100px;
  495. }
  496. .config-type{
  497. font-size: 14px;
  498. color: #333333;
  499. display: flex;
  500. align-items: center;
  501. justify-content: flex-start;
  502. padding: 10px 0;
  503. .el-checkbox{
  504. margin-left: 10px;
  505. }
  506. }
  507. .editForm{
  508. display: grid;
  509. grid-template-columns: repeat(2, 1fr);
  510. gap: 0;
  511. .flex-row{
  512. display: flex;
  513. align-items: center;
  514. :deep(.el-radio){
  515. margin-right: 6px !important;
  516. }
  517. :deep(.el-radio__label){
  518. padding-left: 4px;
  519. }
  520. }
  521. :deep(.el-form-item) {
  522. margin-bottom: 0;
  523. .el-form-item__label {
  524. width: 120px !important;
  525. padding-right: 0 !important;
  526. background: #FBFCFF;
  527. border: 1px solid #EEEEEE;
  528. height: 41px;
  529. line-height: 41px;
  530. padding-left: 5px;
  531. text-align: left;
  532. }
  533. .el-form-item__content {
  534. width: 190px;
  535. position: relative;
  536. height: 41px;
  537. background: #FFFFFF;
  538. padding-left: 7px;
  539. border: 1px solid #EEEEEE;
  540. .el-input__wrapper {
  541. box-shadow: none;
  542. }
  543. .error-msg{
  544. display: none;
  545. position: absolute;
  546. top: 41px;
  547. top: 28px;
  548. left: 8px;
  549. z-index: 22;
  550. color: #dc2626;
  551. font-size: 12px;
  552. }
  553. &:hover{
  554. .error-msg{
  555. display: block;
  556. }
  557. }
  558. // 确保number类型输入框的上下箭头始终显示
  559. input[type="number"]::-webkit-inner-spin-button,
  560. input[type="number"]::-webkit-outer-spin-button {
  561. opacity: 1;
  562. height: 28px;
  563. position: absolute;
  564. top: 2px;
  565. right: 2px;
  566. cursor: pointer;
  567. }
  568. input[type="number"] {
  569. -moz-appearance: number-input; /* Firefox */
  570. }
  571. }
  572. }
  573. }
  574. </style>