Przeglądaj źródła

Merge remote-tracking branch 'origin/dev-frontend' into dev-frontend

panqiuyao 9 miesięcy temu
rodzic
commit
5139efa148

+ 3 - 2
frontend/package.json

@@ -10,10 +10,10 @@
   },
   "dependencies": {
     "@types/axios": "0.14.4",
-    "axios": "1.7.9",
+    "axios": "^1.8.3",
+    "element-plus": "2.1.7",
     "pinia": "3.0.1",
     "pinia-plugin-persistedstate": "4.2.0",
-    "element-plus": "2.1.7",
     "vue": "3.5.13",
     "vue-router": "4.5.0"
   },
@@ -21,6 +21,7 @@
     "@types/node": "22.13.5",
     "@vitejs/plugin-vue": "5.2.1",
     "@vue/tsconfig": "0.7.0",
+    "sass-embedded": "^1.85.1",
     "typescript": "5.7.2",
     "vite": "6.2.0",
     "vue-tsc": "2.2.4"

BIN
frontend/src/assets/images/setting/folder.png


BIN
frontend/src/assets/images/setting/icon1.png


BIN
frontend/src/assets/images/setting/icon1a.png


BIN
frontend/src/assets/images/setting/icon2.png


BIN
frontend/src/assets/images/setting/icon2a.png


BIN
frontend/src/assets/images/setting/icon3.png


BIN
frontend/src/assets/images/setting/icon3a.png


BIN
frontend/src/assets/images/setting/icon4.png


BIN
frontend/src/assets/images/setting/icon4a.png


+ 8 - 0
frontend/src/router/index.ts

@@ -12,6 +12,14 @@ const routes: RouteRecordRaw[] = [
         component: () => import("@/views/Home/index.vue"),
     },
     {
+        path: "/setting",
+        name: "setting",
+        component: () => import("@/views/Setting/index.vue"),
+        meta: {
+            title: '设置'
+        }
+    },
+    {
         path: "/photography/check",
         name: "PhotographyCheck",
         component: () => import("@/views/Photography/check.vue"),

+ 1 - 1
frontend/src/styles/index.scss

@@ -5,7 +5,7 @@
 .button--primary1{
   color: #fff !important;
   background: linear-gradient(135deg, #2FB0FF 0%, #B863FB 100%) !important;
-
+  cursor: pointer;
   border:none !important;
   border-radius: 4px;
   &.disabled{

+ 7 - 0
frontend/src/utils/appfun.ts

@@ -0,0 +1,7 @@
+import { ossResize, ossImageInfo } from './oss'
+export  {
+  // 格式化图片
+  ossResize,
+  // 获取图片信息
+  ossImageInfo,
+} 

+ 117 - 0
frontend/src/utils/oss.ts

@@ -0,0 +1,117 @@
+
+import axios from "axios";
+
+/**
+ * oss resize 参数
+ * 详情见 https://help.aliyun.com/document_detail/44688.html?spm=a2c4g.11186623.6.751.7434663c1Ne07e
+ */
+
+interface OSSResizeOptions {
+  scale?: number;
+  w?: number;
+  h?: number;
+  watermark?: string;
+  [key: string]: any;
+}
+
+interface OSSImageInfoOptions {
+  [key: string]: any;
+}
+
+interface ImageInfo {
+  [key: string]: any;
+}
+
+
+
+function createParmas(key: string, value: any) {
+  return `${key}_${value}`
+}
+
+export function ossResize(url: string, options: OSSResizeOptions = {}): string {
+  if (!url) return ''
+  try {
+    const target = new URL(url)
+    const parmas = target.searchParams
+
+    const list = ['image/resize']
+    //scale 追加scale 参数 默认为2
+    if(options.scale === undefined){
+      options.scale  = 2
+    }
+    if(options.w ){
+      options.w = options.w*options.scale
+    }
+    if(options.h){
+      options.h = options.h*options.scale
+    }
+
+
+/*
+    // 水印
+    if (options.watermark) {
+      list.push(
+        createParmas('watermark', {
+          ...options.watermark,
+        })
+      )
+    }
+
+*/
+
+
+    Object.keys(options).forEach((key) => {
+      if(!['watermark','scale'].includes(key)){
+        const value = options[key]
+        list.push(createParmas(key, value))
+      }
+
+    })
+
+
+    const watermark = []
+    if (options.watermark) {
+      watermark.push('image/watermark')
+      watermark.push('image_' + options.watermark)
+    }
+
+    let str = list.join(',')
+    if(watermark.length  >0){
+      if(str){
+        str+= ','+watermark.join(',')
+      }else{
+        str+= watermark.join(',')
+      }
+    }
+    parmas.set('x-oss-process',str + '/quality,Q_80')
+
+    return target.toString()
+  } catch (error) {
+    console.warn(url)
+    console.warn(error)
+    return url
+  }
+}
+
+
+
+export async function ossImageInfo(url: string, options: OSSImageInfoOptions = {}): Promise<ImageInfo | undefined> {
+  if (!url) return ''
+  try {
+    const target = new URL(url)
+    const parmas = target.searchParams
+    const list = ['image/info']
+    Object.keys(options).forEach((key) => {
+      const value = options[key]
+      list.push(createParmas(key, value))
+    })
+    parmas.set('x-oss-process', list.join(',') + '/quality,Q_80')
+    const ossUrl = target.toString()
+    const { data } = await axios.get(ossUrl)
+    return data
+  } catch (error) {
+    console.error(error)
+    return undefined
+  }
+}
+

+ 205 - 99
frontend/src/views/Photography/shot.vue

@@ -6,16 +6,9 @@
         <div class="step-one flex-col justify-between">
           <div class="step-header flex-row">
             <span class="step-title">第一步:获取商品货号</span>
-            <img
-              class="step-icon"
-              referrerpolicy="no-referrer"
-              src="@/assets/images/Photography/step1-icon.png"
-            />
-            <img
-              class="step-divider"
-              referrerpolicy="no-referrer"
-              src="@/assets/images/Photography/step-divider-line.png"
-            />
+            <img class="step-icon" referrerpolicy="no-referrer" src="@/assets/images/Photography/step1-icon.png" />
+            <img class="step-divider" referrerpolicy="no-referrer"
+              src="@/assets/images/Photography/step-divider-line.png" />
           </div>
           <div class="step-content flex-row justify-between">
             <div class="method-container flex-col">
@@ -26,11 +19,8 @@
               <div class="scan-method flex-row justify-between">
                 <div class="remote-control flex-col">
                   <div class="scan-button flex-col"></div>
-                  <img
-                    class="scan-line"
-                    referrerpolicy="no-referrer"
-                    src="@/assets/images/Photography/remote-scan-line.png"
-                  />
+                  <img class="scan-line" referrerpolicy="no-referrer"
+                    src="@/assets/images/Photography/remote-scan-line.png" />
                 </div>
                 <span class="scan-label">遥控器扫描键</span>
               </div>
@@ -39,30 +29,23 @@
                 <span class="method-description">手工输入货号</span>
               </div>
               <div class="input-container flex-row">
-                <el-input  class="input-item" v-model="input2" placeholder="请输入货号">
+                <el-input class="input-item" v-model="input2" placeholder="请输入货号">
                   <template #append>
-                    <el-button class="input-button"  type="primary" @click="input2 = ''">确认</el-button>
+                    <el-button class="input-button" type="primary" @click="input2 = ''">确认</el-button>
                   </template>
                 </el-input>
-         
+
               </div>
             </div>
-            <img
-              class="remote-image"
-              referrerpolicy="no-referrer"
-              src="@/assets/images/Photography/remote-control.png"
-            />
+            <img class="remote-image" referrerpolicy="no-referrer"
+              src="@/assets/images/Photography/remote-control.png" />
           </div>
         </div>
         <div class="step-two flex-col justify-between">
           <span class="step-title">第二步:启动拍摄(根据左右脚按遥控器左右键启动)</span>
           <div class="shooting-container flex-col">
             <div class="shooting-tips flex-row justify-between">
-              <img
-                class="info-icon"
-                referrerpolicy="no-referrer"
-                src="@/assets/images/Photography/info-icon.png"
-              />
+              <img class="info-icon" referrerpolicy="no-referrer" src="@/assets/images/Photography/info-icon.png" />
               <span class="tips-text">遥控左右按键可启动拍摄,中间按钮可在拍摄5张主图后解锁,用于拍摄自定义图</span>
             </div>
             <span class="left-foot-text">遥控器左键:控制左脚鞋启动拍摄</span>
@@ -71,73 +54,156 @@
                 <div class="left-button flex-col"></div>
                 <div class="right-button flex-col"></div>
               </div>
-              <img
-                class="left-button-image"
-                referrerpolicy="no-referrer"
-                src="@/assets/images/Photography/remote-left-button.png"
-              />
-              <img
-                class="right-button-image"
-                referrerpolicy="no-referrer"
-                src="@/assets/images/Photography/remote-right-button.png"
-              />
+              <img class="left-button-image" referrerpolicy="no-referrer"
+                src="@/assets/images/Photography/remote-left-button.png" />
+              <img class="right-button-image" referrerpolicy="no-referrer"
+                src="@/assets/images/Photography/remote-right-button.png" />
             </div>
             <span class="right-foot-text">遥控器右键:控制右脚鞋启动拍摄</span>
           </div>
         </div>
-        <div class="history-section flex-col justify-end">
+        <div class="history-section flex-col">
           <span class="history-title">拍摄历史</span>
-          <img
-            class="divider-line"
-            referrerpolicy="no-referrer"
-            src="@/assets/images/Photography/divider-line.png"
-          />
-          <div class="empty-state flex-col justify-between">
+          <img class="divider-line" referrerpolicy="no-referrer" src="@/assets/images/Photography/divider-line.png" />
+          <div class="history-warp">
+            <div class="history-item " style="padding:10px;">
+              <div class="flex-item left c-333">货号:AU7729 8192 9291</div>
+              <el-skeleton class="mar-top-10" style="width: 100%" :loading="loading" animated :throttle="500">
+                <template #template>
+                  <div class="flex top  left">
+                    <el-skeleton-item variant="image" style="width: 146px; height: 146px" />
+                    <div style=" flex: 1; height: 100%; margin-top: -6px;" class="flex top wrap between">
+                      <el-skeleton-item v-for="i in 4" :key="i" variant="image"
+                        style="width: 70px; height: 70px;margin:  6px 0 0 6px; " />
+                    </div>
+                  </div>
+                </template>
+                <template #default>
+                  <div class="flex top  left">
+                    <el-popover v-if="test_image_url" width="280" height="280" trigger="hover">
+                      <template #reference>
+                        <el-image :src="ossResize(test_image_url, {
+                          m: 'fill',
+                          h: 146,
+                          w: 146
+                        })" fit="contain" class="cur-p" style="width: 146px; height: 146px" />
+                      </template>
+                      <el-image style="width: 250px;height: 250px" fit="contain" :src="ossResize(test_image_url, {
+                        m: 'fill',
+                        h: 250,
+                        w: 250
+                      })
+                        " />
+                    </el-popover>
+                    <div style=" flex: 1; height: 100%; margin-top: -6px;" class="flex top wrap between">
+                      <template v-for="i in 4" :key="i">
+                        <el-popover v-if="test_image_url" width="280" height="280" trigger="hover">
+                          <template #reference>
+                            <el-image :src="ossResize(test_image_url, {
+                              m: 'fill',
+                              h: 80,
+                              w: 80
+                            })" fit="contain" class="cur-p" style="width: 70px; height: 70px;margin:  6px 0 0 6px;" />
+                          </template>
+                          <el-image style="width: 250px;height: 250px" fit="contain" :src="ossResize(test_image_url, {
+                            m: 'fill',
+                            h: 250,
+                            w: 250
+                          })
+                            " />
+                        </el-popover>
+                      </template>
+                    </div>
+                  </div>
+                </template>
+              </el-skeleton>
+            </div>
+            <template v-for="i in 5" :key="i">
+              <img class="divider-line" referrerpolicy="no-referrer"
+                src="@/assets/images/Photography/divider-line.png" />
+              <div class="history-item" style="padding:10px;">
+                <div class="flex-item left c-333">货号:AU7729 8192 9291</div>
+                <el-skeleton class="mar-top-10" style="width: 100%" :loading="loading" animated :throttle="500">
+                  <template #template>
+                    <div class="flex top  left">
+                      <el-skeleton-item variant="image" style="width: 146px; height: 146px" />
+                      <div style=" flex: 1; height: 100%; margin-top: -6px;  margin-left: 8px;"
+                        class="flex top wrap between">
+                        <el-skeleton-item v-for="i in 4" :key="i" variant="image"
+                          style="width: 70px; height: 70px;margin:  6px 0 0 0px; " />
+                      </div>
+                    </div>
+                    <div style=" flex: 1; height: 100%; margin-top: 4px;" class="flex top wrap between">
+                      <el-skeleton-item v-for="i in 4" :key="i" variant="image"
+                        style="width: 70px; height: 70px;margin:  6px 0 0 0px; " />
+                    </div>
+                  </template>
+                  <template #default>
+                    <div class="flex top  left">
+                      <el-image :src="ossResize(test_image_url, {
+                        m: 'fill',
+                        h: 80,
+                        w: 80
+                      })" fit="contain" style="width: 146px; height: 146px" />
+                      <div style=" flex: 1; height: 100%; margin-top: -6px;  margin-left: 8px;"
+                        class="flex top wrap between">
+                        <el-image v-for="i in 4" :key="i" :src="ossResize(test_image_url, {
+                          m: 'fill',
+                          h: 80,
+                          w: 80
+                        })" fit="contain" style="width: 70px; height: 70px;margin:  6px 0 0 0px; " />
+                      </div>
+                    </div>
+                    <div style=" flex: 1; height: 100%; margin-top: 4px; margin-left: -6px;" class="flex top wrap left">
+                      <el-image v-for="i in 6" :key="i" :src="ossResize(test_image_url, {
+                        m: 'fill',
+                        h: 80,
+                        w: 80
+                      })" fit="contain" style="width: 70px; height: 70px; margin: 6px 0 0 7px; " />
+                    </div>
+                  </template>
+                </el-skeleton>
+              </div>
+
+            </template>
+          </div>
+
+          <!-- 无数据 -->
+          <!-- <div  class="empty-state flex-col justify-between">
             <img
               class="empty-icon"
               referrerpolicy="no-referrer"
               src="@/assets/images/Photography/empty-state-icon.png"
             />
             <span class="empty-text">暂无数据</span>
-          </div>
-          <div class="next-step button--primary1 flex-col"><span class="next-step-text">拍摄完毕,进入下一步处理</span></div>
+          </div> -->
+          <div @click="loading = !loading" class="next-step button--primary1 flex-col"><span
+              class="next-step-text">拍摄完毕,进入下一步处理</span></div>
         </div>
       </div>
-      <img
-        class="camera-image"
-        referrerpolicy="no-referrer"
-        src="@/assets/images/Photography/camera-icon.png"
-      />
+      <img class="camera-image" referrerpolicy="no-referrer" src="@/assets/images/Photography/camera-icon.png" />
       <div class="step-number-two flex-col"><span class="step-text">2</span></div>
     </div>
   </div>
 </template>
-<script>
-export default {
-  data() {
-    return {
-      constants: {}
-    };
-  },
-  methods: {}
-};
+<script setup lang="ts">
+import { ref } from 'vue'
+import { ossResize } from '@/utils/appfun'
+const input2 = ref('')
+const loading = ref(true)
+const test_image_url = ref('https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png')
+
+
 </script>
-<style scoped lang="scss"  >
+
+<style scoped lang="scss">
 .photography-page {
   background-color: rgba(255, 255, 255, 1);
   position: relative;
-  width: 1200px;
-  height: 768px;
-  overflow: hidden;
-
   .main-container {
     position: relative;
-    width: 1200px;
-    height: 739px;
     margin-bottom: 1px;
-    .content-wrapper{
-      width: 1180px;
-      height: 738px;
+    .content-wrapper {
       margin-left: 20px;
       .step-number {
         background-color: rgba(22, 119, 255, 1);
@@ -145,6 +211,7 @@ export default {
         height: 32px;
         margin-top: 51px;
         width: 32px;
+
         .text_22 {
           width: 6px;
           height: 22px;
@@ -158,14 +225,17 @@ export default {
           margin: 5px 0 0 13px;
         }
       }
+
       .step-one {
         width: 426px;
         height: 521px;
         margin: 55px 0 0 5px;
+
         .step-header {
           width: 391px;
           height: 24px;
           margin-left: 3px;
+
           .step-title {
             width: 160px;
             height: 24px;
@@ -178,33 +248,40 @@ export default {
             white-space: nowrap;
             line-height: 24px;
           }
+
           .step-icon {
             width: 32px;
             height: 20px;
             margin-top: 4px;
           }
+
           .step-divider {
             width: 191px;
             height: 1px;
             margin: 13px 0 0 8px;
           }
         }
+
         .step-content {
           width: 426px;
           height: 469px;
           margin-top: 28px;
+
           .method-container {
             background-color: rgba(247, 247, 247, 1);
             height: 469px;
             width: 353px;
+
             .auto-method {
               width: 253px;
               height: 24px;
               margin: 28px 0 0 14px;
+
               .text-method-tag {
                 background-color: rgba(0, 174, 30, 1);
                 height: 24px;
                 width: 65px;
+
                 .text_4 {
                   width: 56px;
                   height: 20px;
@@ -219,6 +296,7 @@ export default {
                   margin: 2px 0 0 4px;
                 }
               }
+
               .method-description {
                 width: 182px;
                 height: 20px;
@@ -233,17 +311,19 @@ export default {
                 margin-top: 2px;
               }
             }
+
             .scan-method {
               width: 263px;
               height: 246px;
               margin: 9px 0 0 85px;
+
               .remote-control {
                 height: 246px;
-                background: url(@/assets/images/Photography/left-button.png)
-                  0px 0px no-repeat;
+                background: url(@/assets/images/Photography/left-button.png) 0px 0px no-repeat;
                 background-size: 98px 246px;
                 width: 97px;
                 position: relative;
+
                 .scan-button {
                   background-color: rgba(0, 174, 30, 1);
                   border-radius: 50%;
@@ -251,6 +331,7 @@ export default {
                   height: 27px;
                   margin: 27px 0 0 34px;
                 }
+
                 .scan-line {
                   position: absolute;
                   left: 52px;
@@ -259,6 +340,7 @@ export default {
                   height: 1px;
                 }
               }
+
               .scan-label {
                 width: 96px;
                 height: 22px;
@@ -273,14 +355,17 @@ export default {
                 margin-top: 30px;
               }
             }
+
             .manual-method {
               width: 155px;
               height: 24px;
               margin: 53px 0 0 14px;
+
               .method-tag {
                 background-color: rgba(0, 148, 174, 1);
                 height: 24px;
                 width: 65px;
+
                 .text_7 {
                   width: 56px;
                   height: 20px;
@@ -295,6 +380,7 @@ export default {
                   margin: 2px 0 0 4px;
                 }
               }
+
               .method-description {
                 width: 84px;
                 height: 20px;
@@ -309,22 +395,24 @@ export default {
                 margin-top: 2px;
               }
             }
+
             .input-container {
               width: 260px;
               height: 36px;
               margin: 7px 0 42px 83px;
 
-              .input-item{
-                ::v-deep{
-                  .el-input__inner{
+              .input-item {
+                ::v-deep {
+                  .el-input__inner {
                     height: 36px;
                     line-height: 36px;
                   }
                 }
               }
-           
+
             }
           }
+
           .remote-image {
             width: 61px;
             height: 38px;
@@ -332,10 +420,12 @@ export default {
           }
         }
       }
+
       .step-two {
         width: 384px;
         height: 521px;
         margin: 55px 0 0 7px;
+
         .step-title {
           width: 384px;
           height: 24px;
@@ -348,20 +438,24 @@ export default {
           white-space: nowrap;
           line-height: 24px;
         }
+
         .shooting-container {
           background-color: rgba(247, 247, 247, 1);
           width: 353px;
           height: 469px;
           margin: 28px 0 0 2px;
+
           .shooting-tips {
             width: 325px;
             height: 40px;
             margin: 12px 0 0 15px;
+
             .info-icon {
               width: 16px;
               height: 16px;
               margin-top: 2px;
             }
+
             .tips-text {
               width: 302px;
               height: 40px;
@@ -373,6 +467,7 @@ export default {
               line-height: 20px;
             }
           }
+
           .left-foot-text {
             width: 240px;
             height: 22px;
@@ -386,18 +481,20 @@ export default {
             line-height: 22px;
             margin: 36px 0 0 9px;
           }
+
           .remote-control-container {
             position: relative;
             width: 280px;
             height: 298px;
             margin: 9px 0 0 35px;
+
             .remote-buttons {
               width: 206px;
               height: 233px;
-              background: url(@/assets/images/Photography/right-button.png)
-                100% no-repeat;
+              background: url(@/assets/images/Photography/right-button.png) 100% no-repeat;
               background-size: 100% 100%;
               margin: 30px 0 0 37px;
+
               .left-button {
                 background-color: rgba(0, 174, 30, 1);
                 border-radius: 50%;
@@ -405,6 +502,7 @@ export default {
                 height: 55px;
                 margin: 91px 0 0 1px;
               }
+
               .right-button {
                 background-color: rgba(0, 148, 174, 1);
                 border-radius: 50%;
@@ -413,11 +511,13 @@ export default {
                 margin: 91px 2px 0 93px;
               }
             }
+
             .left-button-image {
               width: 40px;
               height: 148px;
               margin: 150px 0 0 -3px;
             }
+
             .right-button-image {
               position: absolute;
               left: 0;
@@ -426,6 +526,7 @@ export default {
               height: 148px;
             }
           }
+
           .right-foot-text {
             width: 240px;
             height: 22px;
@@ -441,11 +542,12 @@ export default {
           }
         }
       }
+
       .history-section {
         background-color: rgba(234, 236, 237, 1);
-        width: 322px;
+        width: 332px;
         height: 738px;
-        margin-left: 4px;
+
         .history-title {
           width: 64px;
           height: 22px;
@@ -459,20 +561,30 @@ export default {
           line-height: 22px;
           margin: 9px 0 0 10px;
         }
+
         .divider-line {
-          width: 322px;
+          width: 100%;
           height: 1px;
           margin-top: 9px;
         }
+
+        .history-warp {
+          width: 100%;
+          flex-grow: 1;
+          overflow: auto;
+          height: calc(100% - 125px);
+        }
+
         .empty-state {
           width: 56px;
           height: 48px;
-          margin: 253px 0 0 133px;
+
           .empty-icon {
             width: 32px;
             height: 18px;
             margin-left: 12px;
           }
+
           .empty-text {
             width: 56px;
             height: 20px;
@@ -486,28 +598,26 @@ export default {
             margin-top: 10px;
           }
         }
+
         .next-step {
           height: 50px;
-          background: url(@/assets/images/Photography/SketchPng0a50a29c175ab72b0f2d38d430200d3e7fa3837ba2ebd7d0dfedebd005804b3a.png)
-            100% no-repeat;
           background-size: 100% 100%;
-          margin-top: 346px;
-          width: 322px;
+          width: 100%;
+          line-height: 50px;
+
           .next-step-text {
-            width: 192px;
-            height: 22px;
+            width: 100%;
             overflow-wrap: break-word;
             color: rgba(255, 255, 255, 1);
-            font-size: 16px;
             font-weight: NaN;
             text-align: center;
             white-space: nowrap;
-            line-height: 22px;
-            margin: 14px 0 0 65px;
+
           }
         }
       }
     }
+
     .camera-image {
       position: absolute;
       left: 304px;
@@ -515,6 +625,7 @@ export default {
       width: 111px;
       height: 111px;
     }
+
     .step-number-two {
       background-color: rgba(22, 119, 255, 1);
       border-radius: 50%;
@@ -523,6 +634,7 @@ export default {
       position: absolute;
       left: 450px;
       top: 51px;
+
       .step-text {
         width: 9px;
         height: 22px;
@@ -538,12 +650,6 @@ export default {
     }
   }
 }
-
-
- 
-
 </style>
 
-<style lang="scss" scoped>
-
-</style>
+<style lang="scss" scoped></style>

+ 455 - 0
frontend/src/views/Setting/index.vue

@@ -0,0 +1,455 @@
+<template>
+  <div class="container">
+    <nav class="settings-nav">
+      <div class="nav-item" :class="{'active': activeIndex === 0}" @click="activeIndex = 0">
+        <img src="@/assets/images/setting/icon1.png" class="nav-icon" v-if="activeIndex !== 0"/>
+        <img src="@/assets/images/setting/icon1a.png" class="nav-icon" v-else/>
+        <span>基础配置</span>
+      </div>
+      <div class="nav-item" :class="{'active': activeIndex === 1}" @click="activeIndex = 1">
+        <img src="@/assets/images/setting/icon2.png" class="nav-icon" v-if="activeIndex !== 1"/>
+        <img src="@/assets/images/setting/icon2a.png" class="nav-icon" v-else/>
+        <span>拍照设置</span>
+      </div>
+      <div class="nav-item" :class="{'active': activeIndex === 2}" @click="activeIndex = 2">
+        <img src="@/assets/images/setting/icon3.png" class="nav-icon" v-if="activeIndex !== 2"/>
+        <img src="@/assets/images/setting/icon3a.png" class="nav-icon" v-else/>
+        <span>其他设置</span>
+      </div>
+      <div class="nav-item" :class="{'active': activeIndex === 3}" @click="activeIndex = 3">
+        <img src="@/assets/images/setting/icon4.png" class="nav-icon" v-if="activeIndex !== 3"/>
+        <img src="@/assets/images/setting/icon4a.png" class="nav-icon" v-else/>
+        <span>遥控器设置</span>
+      </div>
+    </nav>
+
+    <div class="form-container">
+        <div class="captureBox" v-if="activeIndex === 0">
+            <div class="form-item">
+                <label>canpture_one图片输出文件夹:</label>
+                <div class="input-group">
+                  <el-input style="width: 430px;" type="textarea" :rows="2" v-model="formData.captureOneFolder" readonly></el-input>
+                  <div class="select-btn" @click="selectFolder">
+                   <img src="@/assets/images/setting/folder.png" /> 选择文件夹
+                  </div>
+                </div>
+            </div>
+            <p class="error-text">capture one的导出拍照图像自动和智能拍的待处理图像自不一致,请重新选择</p>
+          </div>
+          <div class="selectBox" v-if="activeIndex === 0">
+                <div class="form-item">
+                    <label>主图尺寸:</label>
+                    <div class="select-wrapper">
+                    <el-select v-model="formData.mainImageSize" placeholder="请选择">
+                      <el-option v-for="item in mainImageSizeList" :key="item.value" :label="item.label" :value="item.value"></el-option>
+                    </el-select>
+                    </div>
+                </div>
+                <div class="form-item">
+                    <label>图片输出格式:</label>
+                    <div class="select-wrapper">
+                    <el-select v-model="formData.imageFormat" placeholder="请选择">
+                      <el-option v-for="item in imageFormatList" :key="item.value" :label="item.label" :value="item.value"></el-option>
+                    </el-select>
+                    </div>
+                </div>
+                <div class="form-item">
+                    <label>图片锐化:</label>
+                    <div class="select-wrapper">
+                    <el-select v-model="formData.imageSharpening" placeholder="请选择">
+                      <el-option v-for="item in imageSharpeningList" :key="item.value" :label="item.label" :value="item.value"></el-option>
+                    </el-select>
+                    </div>
+                </div>
+        </div>
+          <div class="selectBox" style="padding-top: 0px" v-if="activeIndex === 1">
+                <div class="form-item">
+                    <label>重复拍摄警告:</label>
+                    <div class="select-wrapper">
+                    <el-select v-model="formData.repeatWarning" placeholder="请选择">
+                      <el-option v-for="item in repeatWarningList" :key="item.value" :label="item.label" :value="item.value"></el-option>
+                    </el-select>
+                    </div>
+                </div>
+                <div class="form-item">
+                    <label>单次张数警告:</label>
+                    <div class="select-wrapper">
+                    <el-select v-model="formData.singleWarning" placeholder="请选择">
+                      <el-option v-for="item in singleWarningList" :key="item.value" :label="item.label" :value="item.value"></el-option>
+                    </el-select>
+                    </div>
+                </div>
+                <div class="form-item">
+                    <label>累计拍照警告:</label>
+                    <div class="select-wrapper">
+                    <el-select v-model="formData.totalWarning" placeholder="请选择">
+                      <el-option v-for="item in totalWarningList" :key="item.value" :label="item.label" :value="item.value"></el-option>
+                    </el-select>
+                    </div>
+                </div>
+                <div class="form-item">
+                    <label>对焦时间:</label>
+                    <div class="select-wrapper">
+                      <el-input v-model="formData.focusTime" placeholder="请输入">
+                        <template #append>秒</template>
+                      </el-input>
+                    </div>
+                </div>
+                <div class="form-item">
+                    <label>拍照停留:</label>
+                    <div class="select-wrapper">
+                      <el-input v-model="formData.photoTime" placeholder="请输入">
+                        <template #append>秒</template>
+                      </el-input>
+                    </div>
+                </div>
+        </div>
+          <div class="selectBox" style="padding-top: 0px" v-if="activeIndex === 2">
+                <div class="form-item">
+                    <label>产品类型:</label>
+                    <div class="select-wrapper">
+                    <el-select v-model="formData.productType" placeholder="请选择">
+                      <el-option v-for="item in productTypeList" :key="item.value" :label="item.label" :value="item.value"></el-option>
+                    </el-select>
+                    </div>
+                </div>
+                <div class="form-item">
+                    <label>默认抠图模式:</label>
+                    <div class="select-wrapper">
+                    <el-select v-model="formData.defaultCutoutMode" placeholder="请选择">
+                      <el-option v-for="item in defaultCutoutModeList" :key="item.value" :label="item.label" :value="item.value"></el-option>
+                    </el-select>
+                    </div>
+                </div>
+                <div class="form-item">
+                    <label>设备运动速度:</label>
+                    <div class="select-wrapper">
+                    <el-select v-model="formData.deviceSpeed" placeholder="请选择">
+                      <el-option v-for="item in deviceSpeedList" :key="item.value" :label="item.label" :value="item.value"></el-option>
+                    </el-select>
+                    </div>
+                </div>
+                <div class="form-item">
+                    <label>运行模式:</label>
+                    <div class="select-wrapper">
+                    <el-select v-model="formData.runMode" placeholder="请选择">
+                      <el-option v-for="item in runModeList" :key="item.value" :label="item.label" :value="item.value"></el-option>
+                    </el-select>
+                    </div>
+                </div>
+          </div>
+          <div class="selectBox" style="padding-top: 0px" v-if="activeIndex === 3">
+                <div class="form-item">
+                    <label>接收器:</label>
+                    <div class="select-wrapper">
+                    <el-select v-model="formData.receiver" placeholder="请选择">
+                      <el-option v-for="item in receiverList" :key="item.value" :label="item.label" :value="item.value"></el-option>
+                    </el-select>
+                    </div>
+                </div>
+                <div class="form-item">
+                    <label>左:</label>
+                    <div class="select-wrapper">
+                    <el-select v-model="formData.left" placeholder="请选择">
+                      <el-option v-for="item in leftList" :key="item.value" :label="item.label" :value="item.value"></el-option>
+                    </el-select>
+                    </div>
+                </div>
+                <div class="form-item">
+                    <label>右:</label>
+                    <div class="select-wrapper">
+                    <el-select v-model="formData.right" placeholder="请选择">
+                      <el-option v-for="item in rightList" :key="item.value" :label="item.label" :value="item.value"></el-option>
+                    </el-select>
+                    </div>
+                </div>
+                <div class="form-item">
+                    <label>上:</label>
+                    <div class="select-wrapper">
+                    <el-select v-model="formData.up" placeholder="请选择">
+                      <el-option v-for="item in upList" :key="item.value" :label="item.label" :value="item.value"></el-option>
+                    </el-select>
+                    </div>
+                </div>
+                <div class="form-item">
+                    <label>下:</label>
+                    <div class="select-wrapper">
+                    <el-select v-model="formData.down" placeholder="请选择">
+                      <el-option v-for="item in downList" :key="item.value" :label="item.label" :value="item.value"></el-option>
+                    </el-select>
+                    </div>
+                </div>
+          </div>
+      <div class="text-center mt-8">
+        <button class="bg-gradient-to-r from-primary" @click="saveSetting">
+          保存
+        </button>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+// 这里可以添加Vue组件的逻辑
+import { ref } from 'vue';
+
+const folderPath = ref('');
+const activeIndex = ref(0);
+const formData = ref({
+  captureOneFolder: '',
+  mainImageSize: '',
+  imageFormat: '',
+  imageSharpening: '',
+  repeatWarning: '',
+  singleWarning: '',
+  totalWarning: '',
+  focusTime: '',
+  photoTime: '',
+  productType: '',
+  defaultCutoutMode: '',
+  deviceSpeed: '',
+  runMode: '',
+  receiver: '',
+  left: '',
+  right: '',
+  up: '',
+  down: '',
+});
+const mainImageSizeList = ref([
+  { label: '1600', value: '1600' },
+  { label: '1200', value: '1200' },
+  { label: '1024', value: '1024' },
+  { label: '800', value: '800' },
+]);
+const imageFormatList = ref([
+  { label: 'jpg', value: 'jpg' },
+  { label: 'png', value: 'png' },
+  { label: 'jpeg', value: 'jpeg' },
+]);
+const imageSharpeningList = ref([
+  { label: '0', value: '0' },
+  { label: '1', value: '1' },
+  { label: '2', value: '2' },
+  { label: '3', value: '3' },
+]);
+const repeatWarningList = ref([
+  { label: '关闭', value: '0' },
+  { label: '开启', value: '1' },
+]);
+const singleWarningList = ref([
+  { label: '11', value: '11' },
+  { label: '12', value: '12' },
+  { label: '13', value: '13' },
+]);
+const totalWarningList = ref([
+  { label: '1.0', value: '1.0' },
+  { label: '1.5', value: '1.5' },
+  { label: '2.0', value: '2.0' },
+]);
+const productTypeList = ref([
+  { label: '鞋类', value: '1' },
+  { label: '服装', value: '2' },
+  { label: '箱包', value: '3' },
+]);
+const defaultCutoutModeList = ref([
+  { label: '普通抠图', value: '1' },
+  { label: '智能抠图', value: '2' },
+  { label: '手动抠图', value: '3' },
+]);
+const deviceSpeedList = ref([
+  { label: '一档', value: '1' },
+  { label: '二档', value: '2' },
+  { label: '三档', value: '3' },
+]);
+const runModeList = ref([
+  { label: '普通模式', value: '1' },
+  { label: '自动模式', value: '2' },
+  { label: '手动模式', value: '3' },
+]);
+const receiverList = ref([
+  { label: '蓝牙', value: '1' },
+  { label: '2.4G', value: '2' },
+  { label: '5.8G', value: '3' },
+]);
+const leftList = ref([
+  { label: '左脚', value: '1' },
+  { label: '右脚', value: '2' },
+  { label: '左右脚', value: '3' },
+]);
+const rightList = ref([
+  { label: '左脚', value: '1' },
+  { label: '右脚', value: '2' },
+  { label: '左右脚', value: '3' },
+]);
+const upList = ref([
+  { label: '上移', value: '1' },
+  { label: '下移', value: '2' },
+  { label: '左右移', value: '3' },
+]);
+const downList = ref([
+  { label: '上移', value: '1' },
+  { label: '下移', value: '2' },
+  { label: '左右移', value: '3' },
+]);
+
+const selectFolder = () => {
+  // 这里可以添加选择文件夹的逻辑
+  // 由于浏览器安全限制,网页应用无法直接访问本地文件系统
+  // 这里我们可以使用一个模拟的文件选择对话框
+  
+  // 创建一个隐藏的input元素用于选择文件夹
+  const input = document.createElement('input');
+  input.type = 'file';
+  input.webkitdirectory = true; // 允许选择文件夹而不是文件
+  input.directory = true; // 非标准属性,某些浏览器支持
+  
+  // 监听文件选择事件
+  input.onchange = (event) => {
+    const files = event.target.files;
+    if (files && files.length > 0) {
+      // 获取选择的文件夹路径(仅显示第一个文件的目录)
+      const path = files[0].webkitRelativePath.split('/')[0];
+      folderPath.value = path;
+      
+      // 更新表单数据中的captureOneFolder字段
+      formData.value.captureOneFolder = path;
+      
+      // 这里可以添加更新UI或发送到后端的逻辑
+      console.log('选择的文件夹:', path);
+      
+      // 如果需要,可以在这里添加API调用来保存路径到后端
+      // 例如:axios.post('/api/settings/folder', { path: folderPath.value });
+    }
+  };
+  
+  // 触发文件选择对话框
+  input.click();
+}
+const saveSetting = () => {
+  console.log(formData.value);
+}
+</script>
+
+<style lang="scss" scoped>
+body {
+  min-height: 1024px;
+  background: #EAECED;
+}
+.container {
+  margin: 0 auto;
+  background: #EAECED;
+}
+.settings-nav {
+  display: flex;
+  justify-content: center;
+  gap: 40px;
+  padding: 30px 0;
+  background: #EDEFF0;
+  border-bottom: 1px solid rgba(0,0,0,0.1);
+}
+.nav-item {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  cursor: pointer;
+  color: #666;
+  transition: all 0.3s;
+  width: 100px;
+  justify-content: center;
+  height: 70px;
+  font-size: 14px;
+}
+.nav-item.active {
+    background: #DFE2E3;
+    border-radius: 10px;
+    color: #2957FF;
+}
+.nav-item i {
+  font-size: 24px;
+  margin-bottom: 8px;
+  width: 40px;
+  height: 40px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  background: #fff;
+  border-radius: 8px;
+}
+.form-container {
+  border-radius: 12px;
+  padding: 30px;
+  width: 800px;
+  margin: 0 auto;
+}
+.form-item {
+  margin-bottom: 24px;
+  display: flex;
+  align-items: center;
+}
+.form-item label {
+  display: block;
+  min-width: 98px;
+  text-align: right;
+  font-size: 14px;
+  color: #1A1A1A;
+}
+.input-group {
+  display: flex;
+  gap: 12px;
+}
+.input-group input {
+  flex: 1;
+  border: 1px solid #e5e7eb;
+  border-radius: 4px;
+  padding: 8px 12px;
+  font-size: 14px;
+}
+.select-wrapper {
+  position: relative;
+  width: 200px;
+  ::v-deep(.el-input__inner){ 
+    border-radius: 6px;
+  }
+}
+.error-text {
+  color: #dc2626;
+  font-size: 12px;
+  margin-top: 4px;
+}
+.from-primary{
+    width: 150px;
+    margin-top: 30px;
+    height: 40px;
+    color: #FFFFFF;
+    background: linear-gradient( 135deg, #2FB0FF 0%, #B863FB 100%);
+}
+.nav-icon{
+    width: 32px;
+    height: 32px;
+}
+.captureBox{
+  border-bottom: 1px solid rgba(0,0,0,0.1);
+}
+.selectBox{
+    padding-top: 30px;
+    padding-left: 100px;
+    border-bottom: 1px solid rgba(0,0,0,0.1);
+}
+.select-btn{
+  display: flex;
+  align-items: center;
+  flex-shrink: 0;
+  width: 120px;
+  height: 30px;
+  background: #DFE2E3;
+  border-radius: 6px;
+  justify-content: center;
+  font-size: 14px;
+  color: #2957FF;
+  gap: 5px;
+  img{
+    width: 16px;
+    height: 16px;
+  }
+}
+</style>