10 Commits b8e2509ccd ... b9f9ccb597

Author SHA1 Message Date
  Mcal b9f9ccb597 ✨ feat(Order): 优化订单页面布局,调整表格样式并改善分页组件位置 3 days ago
  Mcal bb8d3e4c9e ✨ feat(Layout): 添加页面切换动画效果,优化用户体验;隐藏滚动条 3 days ago
  Mcal 98730ff743 ✨ feat(Menu): 优化路由激活状态判断逻辑,支持多级路径匹配 4 days ago
  Mcal 0d46e4dcfd ✨ feat(Menu): 优化菜单组件,添加点击导航功能并修复选中状态逻辑 4 days ago
  Mcal 0575daf06b ✨ feat: 更新无产品组件,添加图片和文本属性;优化订单页面布局,增加空状态显示 4 days ago
  陈雪 f27afb600a ✨ feat(database): 添加SKU与规格的中间表,并更新数据库接口 4 days ago
  陈雪 51a8797295 Merge remote-tracking branch 'origin/lyz_dev' 4 days ago
  陈雪 de000eb9c4 Merge remote-tracking branch 'origin/wl_dev' 4 days ago
  陈雪 a76afa0fba ✨ feat(database): 移除规格ID字段并添加SKU与规格的中间表 4 days ago
  PIWALIN b83a8aac97 feat:商品页面静态页面 4 days ago

+ 10 - 1
src-tauri/resources/init.sql

@@ -50,7 +50,6 @@ CREATE TABLE
         sku_no TEXT DEFAULT '', -- SKU编号
         logo TEXT DEFAULT '', -- SKU Logo
         goods_id INTEGER NOT NULL DEFAULT 0, -- 商品ID
-        spec_ids TEXT NOT NULL DEFAULT '', -- 规格ID
         stock INTEGER NOT NULL DEFAULT 0, -- 库存
         price REAL NOT NULL DEFAULT 0.00, -- 价格
         line_price REAL NOT NULL DEFAULT 0.00, -- 划线价
@@ -66,4 +65,14 @@ CREATE TABLE
         name TEXT NOT NULL DEFAULT '', -- 规格名称
         value TEXT NOT NULL DEFAULT '', -- 规格值
         status TEXT DEFAULT 'A' -- 状态 (A-Active, D-Deleted)
+    );
+
+-- 创建SKU和规格的中间表
+CREATE TABLE
+    menu_sku_spec (
+        sku_id INTEGER NOT NULL, -- SKU ID
+        spec_id INTEGER NOT NULL, -- 规格ID
+        PRIMARY KEY (sku_id, spec_id),
+        FOREIGN KEY (sku_id) REFERENCES menu_sku (id),
+        FOREIGN KEY (spec_id) REFERENCES menu_spec (id)
     );

BIN
src/assets/img/add.png


+ 152 - 0
src/assets/img/orderList/暂无支付记录.svg

@@ -0,0 +1,152 @@
+<svg width="300" height="300" viewBox="0 0 300 300" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M221.907 124.32C198.938 85.1335 213.007 61.7723 204.573 47.4795C196.14 33.1867 110.67 27.3604 45.9633 96.9904C-16.1935 163.876 39.7499 242.628 106.964 264.929C168.481 285.339 268.184 265.189 275.75 192.113C278.712 163.507 244.876 163.507 221.907 124.32Z" fill="url(#paint0_linear_1121_95317)"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M221.907 124.32C198.938 85.1335 213.007 61.7723 204.573 47.4795C196.14 33.1867 110.67 27.3604 45.9633 96.9904C-16.1935 163.876 39.7499 242.628 106.964 264.929C168.481 285.339 268.184 265.189 275.75 192.113C278.712 163.507 244.876 163.507 221.907 124.32Z" fill="#F67F20"/>
+<mask id="mask0_1121_95317" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="19" y="38" width="257" height="235">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M221.907 124.32C198.938 85.1335 213.007 61.7723 204.573 47.4795C196.14 33.1867 110.67 27.3604 45.9633 96.9904C-16.1935 163.876 39.7499 242.628 106.964 264.929C168.481 285.339 268.184 265.189 275.75 192.113C278.712 163.507 244.876 163.507 221.907 124.32Z" fill="white"/>
+</mask>
+<g mask="url(#mask0_1121_95317)">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M75.8912 66.2383C75.8912 66.2383 116.049 169.805 95.9699 277.091C75.8912 384.377 -56.5622 132.909 55.9459 75.0192C56.9071 75.0192 75.8912 66.2383 75.8912 66.2383Z" fill="#F67F20"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M34.2008 110.402C34.2008 110.402 72.3668 125.348 95.9699 262.672C84.6403 285.051 -14.9862 195.485 25.5806 122.083L34.2008 110.402Z" fill="#F67F20"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M245.9 147.035C245.9 147.035 222.988 179.526 230.625 270C230.625 270 330.755 200.22 253.283 152.667L245.9 147.035Z" fill="#F67F20"/>
+<circle cx="257.813" cy="205.312" r="6.5625" fill="url(#paint1_linear_1121_95317)"/>
+<circle cx="257.813" cy="205.312" r="6.5625" fill="url(#paint2_linear_1121_95317)"/>
+<g filter="url(#filter0_i_1121_95317)">
+<circle cx="172.501" cy="67.5" r="9.375" fill="url(#paint3_linear_1121_95317)"/>
+<circle cx="172.501" cy="67.5" r="9.375" fill="url(#paint4_linear_1121_95317)"/>
+</g>
+<g filter="url(#filter1_i_1121_95317)">
+<circle cx="76.876" cy="101.25" r="11.25" fill="url(#paint5_linear_1121_95317)"/>
+<circle cx="76.876" cy="101.25" r="11.25" fill="url(#paint6_linear_1121_95317)"/>
+</g>
+</g>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M217.152 161.562C217.152 161.562 235.931 173.666 219.179 191.762C202.428 209.858 186.066 238.715 180.216 248.969C174.367 259.222 164.972 244.574 164.972 244.574L202.102 165.254L217.152 161.562Z" fill="url(#paint7_linear_1121_95317)"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M187.511 153.379C187.511 153.379 212.624 159.197 217.152 161.561C217.152 161.561 201.484 165.903 195.348 191.842C189.211 217.781 177.904 251.563 161.451 248.809C144.998 246.056 139.835 221.064 162.735 185.298C175.042 166.075 187.511 153.379 187.511 153.379Z" fill="url(#paint8_linear_1121_95317)"/>
+<g filter="url(#filter2_i_1121_95317)">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M132.362 90C132.362 90 195.257 120.852 213.392 116.169C220.369 114.367 203.004 135.343 174.617 168.675C146.23 202.006 141.05 241.289 158.346 247.921C158.346 247.921 121.097 237.598 106.161 233.86C91.2254 230.123 64.9407 226.121 69.8426 198.75C74.7445 171.379 94.8215 134.756 109.109 120.032C123.397 105.308 130.393 98.098 132.362 90Z" fill="url(#paint9_linear_1121_95317)"/>
+</g>
+<path d="M127.54 113.426L187.591 133.541L186.4 137.097L126.349 116.982L127.54 113.426Z" fill="url(#paint10_linear_1121_95317)"/>
+<path d="M115.543 141.166L167.434 159.406L166.191 162.944L114.3 144.704L115.543 141.166Z" fill="url(#paint11_linear_1121_95317)"/>
+<path d="M108.911 159.393L156.483 174.918L155.319 178.483L107.747 162.958L108.911 159.393Z" fill="url(#paint12_linear_1121_95317)"/>
+<path d="M100.094 178.553L146.5 192.244L145.439 195.841L99.0332 182.149L100.094 178.553Z" fill="url(#paint13_linear_1121_95317)"/>
+<path d="M91.0279 201.543L141.403 216.568L140.331 220.162L89.9561 205.137L91.0279 201.543Z" fill="url(#paint14_linear_1121_95317)"/>
+<ellipse opacity="0.202962" cx="127.867" cy="180.171" rx="33.75" ry="42.1875" transform="rotate(53 127.867 180.171)" fill="url(#paint15_linear_1121_95317)"/>
+<ellipse cx="106.5" cy="164.806" rx="33.75" ry="47.8125" transform="rotate(53 106.5 164.806)" fill="#F67F20"/>
+<path d="M79.4774 191.631C80.8097 189.412 83.6891 188.692 85.9089 190.025C88.0361 191.301 88.7854 193.999 87.6716 196.175L87.5157 196.456L78.4134 211.622C77.0811 213.841 74.2017 214.561 71.982 213.228C69.8548 211.952 69.1054 209.254 70.2192 207.078L70.3751 206.797L79.4774 191.631Z" fill="url(#paint16_linear_1121_95317)"/>
+<path d="M64.5454 207.644C67.2355 203.22 73.0026 201.815 77.4266 204.505C81.7277 207.12 83.1758 212.644 80.7809 217.014L80.5662 217.386L60.6943 250.066C58.0043 254.49 52.2372 255.896 47.8132 253.206C43.5121 250.591 42.064 245.067 44.4589 240.696L44.6736 240.325L64.5454 207.644Z" fill="url(#paint17_linear_1121_95317)"/>
+<ellipse cx="100.875" cy="159.181" rx="33.75" ry="47.8125" transform="rotate(53 100.875 159.181)" fill="url(#paint18_linear_1121_95317)"/>
+<ellipse cx="100.112" cy="158.664" rx="25.3125" ry="40.3125" transform="rotate(53 100.112 158.664)" fill="url(#paint19_linear_1121_95317)"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M84.8783 138.448C102.659 125.05 123.894 123.239 132.307 134.403C133.786 136.366 134.77 138.599 135.291 141.019C125.634 133.046 106.645 135.66 90.5033 147.823C75.8498 158.866 68.1149 174.332 70.5565 185.68C69.5763 184.872 68.6921 183.954 67.9168 182.925C59.5036 171.76 67.0975 151.847 84.8783 138.448Z" fill="#F67F20"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M132.307 134.403L132.529 134.712C122.631 127.585 104.29 130.397 88.6283 142.198C71.8768 154.822 64.1669 173.226 70.3655 184.651C70.4197 184.998 70.4835 185.341 70.5565 185.68C69.5763 184.872 68.6921 183.954 67.9168 182.925C59.5036 171.76 67.0975 151.847 84.8783 138.448C102.659 125.05 123.894 123.239 132.307 134.403Z" fill="#F67F20"/>
+<defs>
+<filter id="filter0_i_1121_95317" x="163.126" y="58.125" width="18.75" height="18.75" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset/>
+<feGaussianBlur stdDeviation="1.5"/>
+<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
+<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.2 0"/>
+<feBlend mode="normal" in2="shape" result="effect1_innerShadow_1121_95317"/>
+</filter>
+<filter id="filter1_i_1121_95317" x="65.626" y="90" width="22.5" height="22.5" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset/>
+<feGaussianBlur stdDeviation="3"/>
+<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
+<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.2 0"/>
+<feBlend mode="normal" in2="shape" result="effect1_innerShadow_1121_95317"/>
+</filter>
+<filter id="filter2_i_1121_95317" x="68.2422" y="90" width="146.691" height="157.922" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dx="-1"/>
+<feGaussianBlur stdDeviation="1.5"/>
+<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
+<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.5 0"/>
+<feBlend mode="normal" in2="shape" result="effect1_innerShadow_1121_95317"/>
+</filter>
+<linearGradient id="paint0_linear_1121_95317" x1="19.0176" y1="38.4551" x2="19.0176" y2="272.445" gradientUnits="userSpaceOnUse">
+<stop stop-color="#FE8C2E"/>
+<stop offset="1" stop-color="#FE9743"/>
+</linearGradient>
+<linearGradient id="paint1_linear_1121_95317" x1="264.376" y1="205.313" x2="251.251" y2="205.313" gradientUnits="userSpaceOnUse">
+<stop stop-color="#FF821B"/>
+<stop offset="1" stop-color="#FC811C"/>
+</linearGradient>
+<linearGradient id="paint2_linear_1121_95317" x1="254.407" y1="213.997" x2="254.407" y2="196.628" gradientUnits="userSpaceOnUse">
+<stop stop-color="#F67F20"/>
+<stop offset="1" stop-color="white"/>
+</linearGradient>
+<linearGradient id="paint3_linear_1121_95317" x1="181.876" y1="67.5" x2="163.126" y2="67.5" gradientUnits="userSpaceOnUse">
+<stop stop-color="#FF821B"/>
+<stop offset="1" stop-color="#FC811C"/>
+</linearGradient>
+<linearGradient id="paint4_linear_1121_95317" x1="167.634" y1="79.9068" x2="167.634" y2="55.0932" gradientUnits="userSpaceOnUse">
+<stop stop-color="#F67F20"/>
+<stop offset="1" stop-color="white"/>
+</linearGradient>
+<linearGradient id="paint5_linear_1121_95317" x1="88.126" y1="101.25" x2="65.626" y2="101.25" gradientUnits="userSpaceOnUse">
+<stop stop-color="#FF821B"/>
+<stop offset="1" stop-color="#FC811C"/>
+</linearGradient>
+<linearGradient id="paint6_linear_1121_95317" x1="71.0355" y1="116.138" x2="71.0355" y2="86.3619" gradientUnits="userSpaceOnUse">
+<stop stop-color="#F67F20"/>
+<stop offset="1" stop-color="white"/>
+</linearGradient>
+<linearGradient id="paint7_linear_1121_95317" x1="179.903" y1="268.007" x2="179.903" y2="146.747" gradientUnits="userSpaceOnUse">
+<stop stop-color="#F67F20"/>
+<stop offset="0.54" stop-color="white"/>
+</linearGradient>
+<linearGradient id="paint8_linear_1121_95317" x1="164.094" y1="264.424" x2="164.094" y2="137.923" gradientUnits="userSpaceOnUse">
+<stop stop-color="#F67F20"/>
+<stop offset="1" stop-color="white"/>
+</linearGradient>
+<linearGradient id="paint9_linear_1121_95317" x1="104.27" y1="273.456" x2="104.27" y2="64.465" gradientUnits="userSpaceOnUse">
+<stop stop-color="#F67F20"/>
+<stop offset="0.43" stop-color="white"/>
+</linearGradient>
+<linearGradient id="paint10_linear_1121_95317" x1="141.073" y1="140.924" x2="141.073" y2="109.598" gradientUnits="userSpaceOnUse">
+<stop stop-color="#F67F20"/>
+<stop offset="1" stop-color="white"/>
+</linearGradient>
+<linearGradient id="paint11_linear_1121_95317" x1="127.075" y1="166.466" x2="127.075" y2="137.645" gradientUnits="userSpaceOnUse">
+<stop stop-color="#F67F20"/>
+<stop offset="1" stop-color="white"/>
+</linearGradient>
+<linearGradient id="paint12_linear_1121_95317" x1="119.464" y1="181.57" x2="119.464" y2="156.306" gradientUnits="userSpaceOnUse">
+<stop stop-color="#F67F20"/>
+<stop offset="1" stop-color="white"/>
+</linearGradient>
+<linearGradient id="paint13_linear_1121_95317" x1="110.445" y1="198.636" x2="110.445" y2="175.757" gradientUnits="userSpaceOnUse">
+<stop stop-color="#F67F20"/>
+<stop offset="1" stop-color="white"/>
+</linearGradient>
+<linearGradient id="paint14_linear_1121_95317" x1="102.325" y1="223.172" x2="102.325" y2="198.532" gradientUnits="userSpaceOnUse">
+<stop stop-color="#F67F20"/>
+<stop offset="1" stop-color="white"/>
+</linearGradient>
+<linearGradient id="paint15_linear_1121_95317" x1="113.448" y1="180.33" x2="163.566" y2="155.882" gradientUnits="userSpaceOnUse">
+<stop stop-color="#F67F20"/>
+<stop offset="1" stop-color="white"/>
+</linearGradient>
+<linearGradient id="paint16_linear_1121_95317" x1="87.1877" y1="207.189" x2="75.0002" y2="195.002" gradientUnits="userSpaceOnUse">
+<stop stop-color="#F67F20"/>
+<stop offset="1" stop-color="white"/>
+</linearGradient>
+<linearGradient id="paint17_linear_1121_95317" x1="82.5004" y1="208.126" x2="40.3129" y2="242.813" gradientUnits="userSpaceOnUse">
+<stop stop-color="#F67F20"/>
+<stop offset="1" stop-color="white"/>
+</linearGradient>
+<linearGradient id="paint18_linear_1121_95317" x1="83.3531" y1="222.456" x2="83.3531" y2="95.9068" gradientUnits="userSpaceOnUse">
+<stop stop-color="#F67F20"/>
+<stop offset="1" stop-color="white"/>
+</linearGradient>
+<linearGradient id="paint19_linear_1121_95317" x1="86.9706" y1="212.013" x2="86.9706" y2="105.315" gradientUnits="userSpaceOnUse">
+<stop stop-color="#F67F20"/>
+<stop offset="1" stop-color="white"/>
+</linearGradient>
+</defs>
+</svg>

+ 49 - 32
src/components/SearchInput.vue

@@ -1,11 +1,11 @@
-<!-- 搜索框 -->
 <template>
-  <div class="search-container">
+  <div class="search-container" :style="{ width: containerWidth, height: containerHeight }">
     <input
       type="text"
       class="search-input"
-      :placeholder="$t('menu.spicyNoodles')"
+      :placeholder="placeholder"
       v-model="searchQuery"
+      :style="{ height: inputHeight }"
     />
     <div class="search-icon" @click="searchBtn">
     </div>
@@ -15,9 +15,30 @@
 <script setup>
 import { ref } from 'vue'
 
-const searchBtn=()=>{
-  console.log(111);
+// 接收父组件传递过来的 props
+const props = defineProps({
+  containerWidth: {
+    type: String,
+    default: '660px' // 默认值
+  },
+  containerHeight: {
+    type: String,
+    default: '60px' // 默认值
+  },
+  inputHeight: {
+    type: String,
+    default: '40px' // 默认值
+  },
+  placeholder: {
+    type: String,
+    default: 'Search...' // 默认的占位符
+  }
+})
+
+const searchBtn = () => {
+  console.log('Search button clicked');
 }
+
 const searchQuery = ref('')
 </script>
 
@@ -25,36 +46,32 @@ const searchQuery = ref('')
 .search-container {
   display: flex;
   align-items: center;
-  width: 660px;
-  height: 60px;
   border: 1px solid #E6E6E6;
   border-radius: 12px 0 0 12px;
   background-color: #fff;
   margin-bottom: 15px;
-  .search-input {
-    width: 100%;
-    height: 40px;
-    border: none;
-    outline: none;
-    font-size: 16px;
-    padding: 0 10px;
-    border-radius: 30px;
-  }
-  .search-icon {
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    margin-left: 10px;
-    cursor: pointer;
-    width: 66px;
-    height: 66px;
-    background-image: url('../assets/img/search_Icon.png');
-    background-size: contain;
-    background-repeat: no-repeat;
-    background-position: center;
-  }
 }
-// .search-input::placeholder {
-//   color: #999;
-// }
+
+.search-input {
+  width: 100%;
+  border: none;
+  outline: none;
+  font-size: 16px;
+  padding: 0 10px;
+  border-radius: 30px;
+}
+
+.search-icon {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-left: 10px;
+  cursor: pointer;
+  width: 66px;
+  height: 66px;
+  background-image: url('../assets/img/search_Icon.png');
+  background-size: contain;
+  background-repeat: no-repeat;
+  background-position: center;
+}
 </style>

+ 17 - 2
src/components/noProduct.vue

@@ -1,10 +1,25 @@
 <template>
   <div class="w-full h-[80%] flex flex-col items-center justify-center">
-    <img class="w-[45%]" src="/imgs/noFoods.svg" alt="" />
-    <div class="text-[15px] font-semibold">{{ t('menu.noProducts') }}</div>
+    <img class="w-[25%]" :src="img" alt="" />
+    <div class="text-[15px] font-semibold">{{ text }}</div>
   </div>
 </template>
 <script setup>
 import { useI18n } from 'vue-i18n'
+import { defineProps, watch } from 'vue'
 const { t } = useI18n()
+const props = defineProps({
+  img: {
+    type: String,
+    default: '@/assets/imgs/noFoods.svg',
+  },
+  text: {
+    type: String,
+    default: '还没添加菜品哦',
+  },
+})
+console.log(props)
+watch(()=>props.text, (newVal, oldVal) => {
+  console.log('text changed', newVal, oldVal)
+})
 </script>

+ 2 - 1
src/model/index.ts

@@ -1,11 +1,12 @@
 import { MenuCateTable } from './menu_cate'
 import { MenuCommodityTable } from './menu_commodity'
 import { MenuSkuTable } from './menu_sku'
-import { MenuSpecTable } from './menu_spec'
+import { MenuSkuSpec, MenuSpecTable } from './menu_spec'
 
 export interface Database {
   menuCate: MenuCateTable
   menuCommodity: MenuCommodityTable
   menuSku: MenuSkuTable
   menuSpec: MenuSpecTable
+  menuSkuSpec: MenuSkuSpec
 }

+ 0 - 1
src/model/menu_sku.ts

@@ -6,7 +6,6 @@ export interface MenuSkuTable {
   skuNo: string // SKU编号
   logo: string // SKU Logo
   goodsId: number // 商品ID
-  specIds: string // 规格ID
   stock: number // 库存
   price: number // 价格
   linePrice: number // 划线价

+ 10 - 0
src/model/menu_spec.ts

@@ -12,3 +12,13 @@ export interface MenuSpecTable {
 export type MenuSpec = Selectable<MenuSpecTable>
 export type NewMenuSpec = Insertable<MenuSpecTable>
 export type MenuSpecUpdate = Updateable<MenuSpecTable>
+
+// SKU和规格的中间表
+export interface MenuSkuSpecTable {
+  skuId: number // SKU ID
+  specId: number // 规格ID
+}
+
+export type MenuSkuSpec = Selectable<MenuSkuSpecTable>
+export type NewMenuSkuSpec = Insertable<MenuSkuSpecTable>
+export type MenuSkuSpecUpdate = Updateable<MenuSkuSpecTable>

+ 306 - 0
src/views/goods/components/goods-drawer.vue

@@ -0,0 +1,306 @@
+<template>
+  <div>
+    <el-drawer v-model="show" :show-close="false" direction="rtl" size="700px">
+      <template #header>
+        <div class="food_title">New Product</div>
+      </template>
+
+      <template #default>
+        <el-form
+          :model="formData"
+          :rules="rules"
+          ref="formRef"
+          label-width="150px"
+          class="upload-wrapper"
+        >
+          <!-- 第一排 -->
+          <div class="upload-section">
+            <div class="upload_img">
+              <div class="upload-label">Product Image </div>
+              <el-form-item prop="img">
+              <el-upload
+                class="upload-box"
+                action="https://jsonplaceholder.typicode.com/posts/"
+                accept="image/*"
+                list-type="picture-card"
+                :auto-upload="false"
+                :on-preview="handlePreview"
+                :on-remove="handleRemove"
+                :on-change="handleChange"
+                :file-list="fileList"
+                :limit="1"
+                :before-upload="beforeUpload"
+              >
+                <i>
+                  <img src="../../../assets/img/add.png" alt="" />
+                </i>
+                <span class="upload-text">Click to upload</span>
+              </el-upload>
+              </el-form-item>
+              <div class="upload-tip">Please upload a 1:1 image in PNG, JPG, JPEG format</div>
+            </div>
+            <!-- Product Name -->
+            <div class="upload_input">
+              <div class="upload-label">Product Name</div>
+              <el-form-item prop="productName">
+                <el-input
+                  type="text"
+                  v-model="formData.productName"
+                  autocomplete="off"
+                  placeholder="Please enter the product name"
+                />
+              </el-form-item>
+            </div>
+            <!-- Category -->
+            <div class="upload_section">
+              <div class="upload-label">Category *</div>
+              <el-form-item prop="category">
+                <el-select v-model="formData.category" placeholder="Select" size="large">
+                  <el-option
+                    v-for="item in options"
+                    :key="item.value"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </el-select>
+              </el-form-item>
+            </div>
+          </div>
+
+          <!-- 第二排 -->
+          <div class="input-section">
+            <div class="input-price">
+              <div class="upload-label">Commodity Price *</div>
+              <el-form-item prop="price">
+                <el-input
+                  type="text"
+                  v-model="formData.price"
+                  autocomplete="off"
+                  placeholder="Please enter the commodity price"
+                />
+              </el-form-item>
+            </div>
+            <div class="upload_input">
+              <div class="upload-label">Keywords</div>
+              <el-form-item prop="keywords">
+                <el-input
+                  type="text"
+                  v-model="formData.keywords"
+                  autocomplete="off"
+                  placeholder="Please enter keywords"
+                />
+              </el-form-item>
+            </div>
+            <div class="upload_section">
+              <div class="upload-label">Product Status</div>
+              <el-form-item prop="productStatus">
+                <el-radio-group v-model="formData.productStatus">
+                  <el-radio value="1" size="large">Upper</el-radio>
+                  <el-radio value="2" size="large">Below</el-radio>
+                </el-radio-group>
+              </el-form-item>
+            </div>
+          </div>
+
+          <!--第三排 -->
+          <div class="select-section">
+            <div class="upload-label">Product Specifications *</div>
+            <el-form-item prop="productSpecifications">
+                <el-radio-group v-model="formData.productSpecifications" @change="radioShow">
+                  <el-radio value="1" size="large">Product specifications</el-radio>
+                  <el-radio value="2" size="large">Multiple specifications</el-radio>
+                </el-radio-group>
+            </el-form-item>
+          </div>
+        </el-form>
+        <showRadio  v-show="isShow"/>
+      </template>
+
+      <template #footer>
+        <div style="display: flex; justify-content: space-between">
+          <el-button style="width: 220px; height: 44px" type="primary" @click="cancelClick" plain>
+            Cancel
+          </el-button>
+          <el-button
+            style="width: 408px; height: 44px; background: #f67f20; color: #fff"
+            type="primary"
+            @click="handleSubmit"
+            plain
+          >
+            Save
+          </el-button>
+        </div>
+      </template>
+    </el-drawer>
+
+  </div>
+</template>
+
+<script setup>
+  import { ref,reactive } from 'vue'
+  import showRadio from "./show-radio.vue"
+  const show = defineModel('show')
+  const isShow=ref(false)
+  const cancelClick = () => {
+    show.value = false
+  }
+  const formData = ref({
+    productName: '',
+    category: '',
+    price: '',
+    keywords: '',
+    productStatus: '2',
+    productSpecifications: '1',
+  })
+  const rules = ref({
+    productName: [{ required: true, message: 'Product Name is required', trigger: 'blur' }],
+    category: [{ required: true, message: 'Category is required', trigger: 'change' }],
+    price: [{ required: true, message: 'Commodity Price is required', trigger: 'blur' }],
+    productSpecifications: [
+      { required: true, message: 'Product Specifications are required', trigger: 'change' },
+    ],
+  })
+
+  const options = [
+    { value: '1', label: 'Category 1' },
+    { value: '2', label: 'Category 2' },
+  ]
+  const beforeUpload = (file) => {
+    const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'
+    if (!isJpgOrPng) {
+      this.$message.error('Only JPG/PNG file types are allowed')
+    }
+    return isJpgOrPng
+  }
+
+  const handlePreview = (file) => {
+    console.log('Preview file:', file)
+  }
+
+  const handleRemove = (file, fileList) => {
+    console.log('Removed file:', file)
+  }
+
+  const handleChange = (file, fileList) => {
+    console.log('File changed:', file)
+  }
+
+  const handleSubmit = () => {
+    // const formRef = ref('')
+    // formRef.value.validate((valid) => {
+    //   if (valid) {
+    //     console.log('Form Submitted:', formData.value)
+    //   } else {
+    //     console.log('Form validation failed')
+    //   }
+    // })
+    console.log('Form Submitted:', formData.value)
+
+  }
+
+  const radioShow=(end)=>{
+    isShow.value=true
+    if(end === '2'){
+      isShow.value=true
+    }else{
+      isShow.value=false
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+  :deep(.el-drawer__header) {
+    margin-bottom: 0px !important;
+  }
+  .food_title {
+    height: 56px;
+    font-size: 24px;
+    font-weight: 600;
+    border-bottom: 1px solid #e6e6e6;
+  }
+  .upload-wrapper {
+    width: 100%;
+    height: 380px;
+  }
+  .upload-label {
+    margin-bottom: 15px;
+  }
+  .upload-section {
+    width: 100%;
+    height: 190px;
+    display: flex;
+    justify-content: space-between;
+    :deep(.el-form-item__content){
+      margin-left: 0px !important;
+    }
+  }
+  .upload_img {
+    flex: 1;
+  }
+  .upload_input {
+    margin: 0px 25px 0px 5px;
+    width: 180px;
+  }
+  :deep(.el-input__wrapper) {
+    height: 35px;
+  }
+  .upload_section {
+    width: 180px;
+  }
+
+  .upload-box {
+    :deep(.el-upload) {
+      width: 100px;
+      height: 100px;
+      border: 1px dashed #eeeeee;
+      border-radius: 4px;
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      justify-content: center;
+      cursor: pointer;
+      transition: border-color 0.3s;
+      border-radius: 10px;
+      background: #eeeeee;
+      &:hover {
+        border-color: #409eff;
+      }
+    }
+  }
+  .upload-box i {
+    font-size: 20px;
+    color: #8c939d;
+    margin-bottom: 8px;
+  }
+  .upload-text {
+    font-size: 10px;
+    color: #8c939d;
+  }
+  .upload-tip {
+    font-size: 12px;
+    color: #909399;
+    margin-top: 8px;
+  }
+
+  .input-section {
+    width: 100%;
+    height: 100px;
+    display: flex;
+    justify-content: space-between;
+    :deep(.el-form-item__content){
+      margin-left: 0px !important;
+    }
+  }
+  .input-price {
+    flex: 1;
+    :deep(.el-input) {
+      width: 180px !important;
+    }
+  }
+ .select-section{
+  :deep(.el-form-item__content){
+    margin-left: 0px !important;
+  }
+ }
+
+</style>

+ 7 - 0
src/views/goods/components/show-radio.vue

@@ -0,0 +1,7 @@
+<template>
+  <div>111111111111111111111</div>
+</template>
+
+<script setup></script>
+
+<style lang="scss" scoped></style>

+ 150 - 6
src/views/goods/index.vue

@@ -1,13 +1,157 @@
+<!-- 代码已包含 CSS:使用 TailwindCSS , 安装 TailwindCSS 后方可看到布局样式效果 -->
 <template>
-    <div>
-11111
+  <div class="container">
+    <div class="header">
+        <div class="search-box">
+            <el-input v-model="searchText" placeholder="Enter Keywords To Search" class="search-input" />
+            <div class="search-icon"></div>
+        </div>
+      <el-select v-model="selectedCategory" placeholder="Category" class="select-input">
+        <el-option label="Category 1" value="1" />
+        <el-option label="Category 2" value="2" />
+      </el-select>
+      <el-select v-model="selectedStatus" placeholder="Products for sale" class="select-input">
+        <el-option label="Online" value="online" />
+        <el-option label="Offline" value="offline" />
+      </el-select>
+      <el-button type="danger" class="btn-reset" @click="Reset_Btn">Reset</el-button>
+      <el-button type="danger" class="btn-new"   @click="show = true">New Product</el-button>
     </div>
+    <el-table :data="productList" style="width: 100%">
+      <el-table-column prop="id" label="Id" />
+      <el-table-column label="Product Image">
+        <template #default="scope">
+          <img :src="scope.row.image" :alt="scope.row.name" class="product-img" />
+        </template>
+      </el-table-column>
+      <el-table-column prop="name" label="Product Name" />
+      <el-table-column prop="price" label="Commodity Price">
+        <template #default="scope">${{ scope.row.price }}</template>
+      </el-table-column>
+      <el-table-column prop="sales" label="Sales Volume" />
+      <el-table-column label="State">
+        <template #default="scope">
+          <el-tag :type="scope.row.state === 'Online' ? 'success' : 'danger'">
+            {{ scope.row.state }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column prop="time" label="Time" />
+      <el-table-column label="Operation">
+        <template #default="scope">
+          <el-button type="primary" text>Edit</el-button>
+          <el-button type="danger" text>Delete</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <GoodsDrawer v-model:show="show"></GoodsDrawer>
+  </div>
 </template>
-
 <script setup>
-
+  import { ref } from 'vue'
+import GoodsDrawer from './components/goods-drawer.vue'
+  const show = ref(false)
+  const searchText = ref('')
+  const selectedCategory = ref('')
+  const selectedStatus = ref('')
+  const Reset_Btn=()=>{
+   console.log('重置');
+  }
+  const productList = ref([
+    {
+      id: '00010',
+      image: 'https://ai-public.mastergo.com/ai/img_res/a59d5d07e117eb6d961215c66250fdd2.jpg',
+      name: 'Italian Fettuccine Alfredo',
+      price: '90',
+      sales: '100W',
+      state: 'Online',
+      time: '2024-12-15 15:22:11',
+    },
+    {
+      id: '00009',
+      image: 'https://ai-public.mastergo.com/ai/img_res/d2fa8449384dece57a03a95dd63ce752.jpg',
+      name: 'Classic Spaghetti Carbonara',
+      price: '90',
+      sales: '52W',
+      state: 'Online',
+      time: '2024-12-15 15:22:11',
+    },
+    {
+      id: '00008',
+      image: 'https://ai-public.mastergo.com/ai/img_res/4635661eaf01c5ff6f2eafa6ce127614.jpg',
+      name: 'Spicy Penne Arrabbiata',
+      price: '90',
+      sales: '1W',
+      state: 'Online',
+      time: '2024-12-15 15:22:11',
+    },
+    {
+      id: '00007',
+      image: 'https://ai-public.mastergo.com/ai/img_res/64fbcaa413252850d70af6e06b04783c.jpg',
+      name: 'Traditional Beef Lasagna',
+      price: '90',
+      sales: '999',
+      state: 'Online',
+      time: '2024-12-15 15:22:11',
+    },
+  ])
 </script>
+<style scoped lang="scss">
+  .container {
+    max-width: 1704px;
+    padding: 16px;
+  }
+
+  .header {
+    display: flex;
+    align-items: center;
+    gap: 16px;
+    margin-bottom: 12px;
+  }
+  .search-box {
+  display: flex;
+  align-items: center;
+  height: 60px;
+  position: relative;
+  .search-input {
+    width: 240px;
+  }
+  .search-icon {
+    position: absolute;
+    margin-left: 210px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    cursor: pointer;
+    width: 32px;
+    height: 32px;
+    background-image: url('../../assets/img/search_Icon.png'); 
+    background-size: contain;
+    background-repeat: no-repeat;
+    background-position: center;
+  }
+  }
+  .select-input {
+    width: 180px;
+  }
+  .btn-new {
+    margin-left: auto !important;
+  }
+
+  .product-img {
+    width: 48px;
+    height: 48px;
+    border-radius: 50%;
+    object-fit: cover;
+  }
 
-<style lang="scss" scoped>
+  :deep(.el-table) {
+    --el-table-border-color: #f0f0f0;
+    --el-table-header-bg-color: #fafafa;
+    --el-table-row-hover-bg-color: #f5f5f5;
+  }
 
-</style>
+  :deep(.el-table .el-table__row:nth-child(even)) {
+    background-color: #fafafa;
+  }
+</style>

+ 17 - 16
src/views/layout/components/Menu.vue

@@ -1,39 +1,40 @@
 <template>
-  <div class="flex flex-col items-center">
+  <div class="flex flex-col items-center cursor-pointer" @click="navigateToRoute">
     <div
       class="rounded-[20px] flex items-center justify-center w-[45px] h-[45px]"
-      :class="[props.info.slected ? 'active' : '']"
+      :class="[isActive ? 'active' : '']"
     >
       <img :src="props.info?.img" class="w-full h-full" />
     </div>
     <div
       class="text-center text-[12px] w-[75px]"
-      :class="[props.info.slected ? 'font-semibold' : '']"
+      :class="[isActive ? 'font-semibold' : '']"
     >
       {{ t(props.info.name) }}
     </div>
   </div>
 </template>
 <script setup>
-import { watch } from 'vue'
+import { watch, computed } from 'vue'
 import router from '../../../router'
 import { useI18n } from 'vue-i18n'
+import { useRoute } from 'vue-router'
+
 const { t, locale } = useI18n()
 const props = defineProps({
   info: { type: Object, required: true },
 })
-watch(
-  () => props,
-  () => {
-    if (props.info.slected) {
-      router.push(props.info.path)
-    }
-  },
-  { deep: true },
-)
-const changeLanguage = (lang) => {
-  locale.value = lang
+const route = useRoute()
+
+const isActive = computed(() => {
+  //根据第一个/后面的字符串判断是否是当前路由
+  return route.path.split('/')[1] === props.info.path.split('/')[1]
+})
+
+const navigateToRoute = () => {
+  router.push(props.info.path)
 }
+
 </script>
 <style scoped>
 .active {
@@ -41,4 +42,4 @@ const changeLanguage = (lang) => {
   background: #f67f20;
   box-shadow: 0px 12.864px 38.593px 0px rgba(234, 124, 105, 0.32);
 }
-</style>
+</style>    

+ 18 - 0
src/views/layout/index.vue

@@ -6,7 +6,9 @@
                 <Menu @click="handleClick(item)" v-for="item in menus" :info="item" />
             </div>
             <div class=" flex-1 overflow-y-auto">
+              <Transition name="slide-right" >
                 <router-view />
+              </Transition>
             </div>
         </div>
     </div>
@@ -63,6 +65,18 @@ function handleClick(m) {
 }
 </script>
 <style scoped lang="scss">
+.slide-right-enter-active,
+.slide-right-leave-active {
+  transition: all 0.5s ease;
+}
+.slide-right-enter-from {
+  opacity: 0;
+  transform: translateX(100%);
+}
+.slide-right-leave-to {
+  opacity: 0;
+  transform: translateX(-100%);
+}
 .main {
   width: 100%;
   height: 100vh;
@@ -80,4 +94,8 @@ function handleClick(m) {
     }
   }
 }
+// 隐藏滚动条
+::-webkit-scrollbar {
+  display: none;
+}
 </style>

+ 2 - 1
src/views/menu/components/menuFood.vue

@@ -12,7 +12,7 @@
       <div class="item">{{ quantity }}</div>
     </div>
     <div class="w-[398px] h-[102px]" v-show="showNumberClose">
-      <Title fontSize="16px">Number</Title>
+      <Title fontSize="16px">{{ $t('menu.number') }}</Title>
       <div class="food_number">
         <div @click="handleChange(-1)">
           <img src="../../../assets//img//minus_Icon.png" alt="" />
@@ -78,6 +78,7 @@
   //   align-items: center;
   // }
   .food_container {
+    margin-top: 10px;
     width: 100%;
     display: flex;
     align-items: center;

+ 5 - 1
src/views/menu/components/order-drawer.vue

@@ -9,7 +9,11 @@
 
       <template #default>
         <div class="scroll">
-          <SearchInput></SearchInput>
+          <SearchInput
+            :containerWidth="'660px'"
+            :inputHeight="'30px'"
+            :placeholder="$t('menu.spicyNoodles')"
+          />
           <!-- 判断从那点击进来 Search点击搜索框 -->
           <div v-if="type === 'Search'">
             <!-- 判断foodItems 显示图片 -->

+ 152 - 113
src/views/menu/index.vue

@@ -4,33 +4,24 @@
       <div class="w-full h-full overflow-y-auto relative hide-bar">
         <div class="sticky top-0 w-full bg-[#fff] p-[10px]">
           <div class="h-[60px] flex justify-between items-center">
-            <div
-              class="flex-1 h-full pr-[10px] flex items-center justify-between cursor-pointer overflow-hidden"
-            >
+            <div class="flex-1 h-full pr-[10px] flex items-center justify-between cursor-pointer overflow-hidden">
               <div
-                class="text-[#999] shrink-0 flex items-center justify-center h-[34px] w-[44px] border border-[#e6e6e6] rounded-[12px]"
-              >
+              @click="handleArrow(-1)"
+                class="text-[#999] shrink-0 flex items-center justify-center h-[34px] w-[44px] border border-[#e6e6e6] rounded-[12px]">
                 <el-icon>
                   <ArrowLeft />
                 </el-icon>
               </div>
-              <div
-                ref="scrollRef"
-                class="overflow-x-auto bg-[#fff]"
-                style="width: calc(100% - 108px)"
-              >
+              <div ref="scrollRef" class="overflow-x-auto bg-[#fff]" style="width: calc(100% - 108px)">
                 <div ref="" class="flex flex-nowrap items-center">
-                  <div
-                    v-for="item in products"
-                    class="flex items-center shrink-0 mr-[20px] h-[34px]"
-                  >
+                  <div @click="selectMenu(index)" v-for="(item,index) in products" class="flex items-center p-2 shrink-0 mr-[20px] h-[34px]" :class="[currentIndex == index ? 'active' : '' ]">
                     {{ item.name }}
                   </div>
                 </div>
               </div>
               <div
-                class="text-[#999] shrink-0 flex items-center justify-center h-[34px] w-[44px] border border-[#e6e6e6] rounded-[12px]"
-              >
+              @click="handleArrow(1)"
+                class="text-[#999] shrink-0 flex items-center justify-center h-[34px] w-[44px] border border-[#e6e6e6] rounded-[12px]">
                 <el-icon>
                   <ArrowRight />
                 </el-icon>
@@ -38,25 +29,14 @@
             </div>
           </div>
           <div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6">
-            <div
-              v-for="product in products"
-              :key="product.id"
-              @click="show = true"
-              class="bg-white rounded-xl shadow-sm transition-transform"
-            >
-              <div
-                class="relative flex items-center bg-[#fef8f4] justify-center mb-4 rounded overflow-hidden"
-              >
-                <img
-                  :src="product.image"
-                  :alt="product.name"
-                  class="w-25 h-25 my-1 object-cover rounded-full"
-                />
+            <div v-for="(product,index) in products" :key="product.id" @click="show = true"
+              class="bg-white rounded-xl shadow-sm transition-transform" >
+              <div class="relative flex items-center bg-[#fef8f4] justify-center mb-4 rounded overflow-hidden">
+                <img :src="product.image" :alt="product.name" class="w-25 h-25 my-1 object-cover rounded-full" />
               </div>
               <div class="text-left px-2">
                 <h3
-                  class="text-gray-800 font-medium text-sm mb-2 text-container w-full text-nowrap line-clamp-2 sm:line-clamp-1 md:line-clamp-2 lg:line-clamp-3"
-                >
+                  class="text-gray-800 font-medium text-sm mb-2 text-container w-full text-nowrap line-clamp-2 sm:line-clamp-1 md:line-clamp-2 lg:line-clamp-3">
                   {{ product.name }}
                 </h3>
                 <p class="text-orange-500 font-semibold">${{ product.price.toFixed(2) }}</p>
@@ -74,93 +54,152 @@
 
   </div>
 </template>
-<script lang="ts" setup>
-  import { ref, onMounted, nextTick } from 'vue'
-  import { useI18n } from 'vue-i18n'
-  import { ArrowRight, ArrowLeft } from '@element-plus/icons-vue'
-  import rightOrder from './components/rightOrder/rightOrder.vue'
-  import OrderDrawer from './components/order-drawer.vue'
-  import deskDrawer from './components/desk-drawer.vue'
-  const { t } = useI18n()
-  const scrollRef = ref(null)
+<script  setup>
+import { ref, onMounted, nextTick } from 'vue'
+import { useI18n } from 'vue-i18n'
+import { ArrowRight, ArrowLeft } from '@element-plus/icons-vue'
+import rightOrder from './components/rightOrder/rightOrder.vue'
+import OrderDrawer from './components/order-drawer.vue'
+import deskDrawer from './components/desk-drawer.vue'
+const { t } = useI18n()
 
-  const show = ref(false)
+const show = ref(false)
 
-  onMounted(() => {})
+onMounted(() => { })
 
-  const products = ref([
-    {
-      id: 1,
-      name: 'Spicy Seasoned Seafood Noodles',
-      price: 2.29,
-      image: 'https://ai-public.mastergo.com/ai/img_res/e53b11a05b7778db2bc50338e47047c4.jpg',
-    },
-    {
-      id: 2,
-      name: 'Grilled Salmon Bowl',
-      price: 3.49,
-      image: 'https://ai-public.mastergo.com/ai/img_res/07e4619fc2f26fe9f6a0afaebc47dceb.jpg',
-    },
-    {
-      id: 3,
-      name: 'Teriyaki Chicken Rice',
-      price: 2.99,
-      image: 'https://ai-public.mastergo.com/ai/img_res/1709d2e0e3495f8089da24be4ad2d26a.jpg',
-    },
-    {
-      id: 4,
-      name: 'Vegetable Stir Fry Noodles',
-      price: 2.49,
-      image: 'https://ai-public.mastergo.com/ai/img_res/043e50f136a6ec7f5f37eb448cf298c7.jpg',
-    },
-    {
-      id: 5,
-      name: 'Spicy Tuna Poke Bowl',
-      price: 3.99,
-      image: 'https://ai-public.mastergo.com/ai/img_res/7f8ad399ad651c8de6896bc611be1936.jpg',
-    },
-    {
-      id: 6,
-      name: 'Beef Bulgogi Bowl',
-      price: 3.79,
-      image: 'https://ai-public.mastergo.com/ai/img_res/49b0d0fbf6654dcef422a7e3334c8b6a.jpg',
-    },
-    {
-      id: 7,
-      name: 'Shrimp Pad Thai',
-      price: 3.29,
-      image: 'https://ai-public.mastergo.com/ai/img_res/ca1fef96dffcfa401768314721606c8f.jpg',
-    },
-    {
-      id: 8,
-      name: 'Miso Ramen Bowl',
-      price: 2.89,
-      image: 'https://ai-public.mastergo.com/ai/img_res/210debe79bb22fec1944cab575f2759f.jpg',
-    },
-  ])
+const products = ref([
+  {
+    id: 1,
+    name: 'Spicy Seasoned Seafood Noodles',
+    price: 2.29,
+    image: 'https://ai-public.mastergo.com/ai/img_res/e53b11a05b7778db2bc50338e47047c4.jpg',
+  },
+  {
+    id: 2,
+    name: 'Grilled Salmon Bowl',
+    price: 3.49,
+    image: 'https://ai-public.mastergo.com/ai/img_res/07e4619fc2f26fe9f6a0afaebc47dceb.jpg',
+  },
+  {
+    id: 3,
+    name: 'Teriyaki Chicken Rice',
+    price: 2.99,
+    image: 'https://ai-public.mastergo.com/ai/img_res/1709d2e0e3495f8089da24be4ad2d26a.jpg',
+  },
+  {
+    id: 4,
+    name: 'Vegetable Stir Fry Noodles',
+    price: 2.49,
+    image: 'https://ai-public.mastergo.com/ai/img_res/043e50f136a6ec7f5f37eb448cf298c7.jpg',
+  },
+  {
+    id: 5,
+    name: 'Spicy Tuna Poke Bowl',
+    price: 3.99,
+    image: 'https://ai-public.mastergo.com/ai/img_res/7f8ad399ad651c8de6896bc611be1936.jpg',
+  },
+  {
+    id: 6,
+    name: 'Beef Bulgogi Bowl',
+    price: 3.79,
+    image: 'https://ai-public.mastergo.com/ai/img_res/49b0d0fbf6654dcef422a7e3334c8b6a.jpg',
+  },
+  {
+    id: 7,
+    name: 'Shrimp Pad Thai',
+    price: 3.29,
+    image: 'https://ai-public.mastergo.com/ai/img_res/ca1fef96dffcfa401768314721606c8f.jpg',
+  },
+  {
+    id: 8,
+    name: 'Miso Ramen Bowl',
+    price: 2.89,
+    image: 'https://ai-public.mastergo.com/ai/img_res/210debe79bb22fec1944cab575f2759f.jpg',
+  },
+])
 
-  // 挂单桌子
-  const deskShow = ref(false)
-  const catgroyClick = () => {
-    deskShow.value = true
-  }
+// 挂单桌子
+const deskShow = ref(false)
+const catgroyClick = () => {
+  deskShow.value = true
+}
+
+const scrollRef = ref(null);
+const currentIndex = ref(0);
+let positions = [];
+
+const recalculatePositions = () => {
+  const flexContainer = scrollRef.value?.firstElementChild;
+  if (!flexContainer) return [];
+  
+  const items = Array.from(flexContainer.children);
+  let total = 0;
+  
+  return items.map((item, index) => {
+    const style = window.getComputedStyle(item);
+    const margin = index < items.length - 1 ? parseFloat(style.marginRight) : 0;
+    const start = total;
+    total += item.offsetWidth + margin;
+    return { start, end: total - margin };
+  });
+};
+
+const scrollToIndex = (index) => {
+  if (!scrollRef.value) return;
+  
+  const containerWidth = scrollRef.value.offsetWidth;
+  const target = positions[index];
+  
+  if (!target) return;
+  
+  const scrollPos = Math.max(0, Math.min(
+    target.start - (containerWidth - (target.end - target.start)) / 2,
+    scrollRef.value.scrollWidth - containerWidth
+  ));
+  
+  scrollRef.value.scrollTo({
+    left: scrollPos,
+    behavior: 'smooth'
+  });
+};
+
+const handleArrow = (direction) => {
+  positions = recalculatePositions();
+  currentIndex.value = Math.max(0, Math.min(
+    currentIndex.value + direction,
+    positions.length - 1
+  ));
+  scrollToIndex(currentIndex.value);
+};
+
+const selectMenu = (index) => {
+  currentIndex.value = index;
+  scrollToIndex(index);
+};
 </script>
 <style scoped>
-  ::-webkit-scrollbar-thumb {
-    background-color: red;
-  }
-  /* 隐藏整个滚动条 */
-  ::-webkit-scrollbar {
-    display: none;
-  }
+.active {
+  background-color: #f67f20;
+  color:white;
+  border-radius: 5px;
+}
+::-webkit-scrollbar-thumb {
+  background-color: red;
+}
 
-  /* 或者仅隐藏滚动条的轨道,保留滑块可操作性,但视觉上不显示滚动条 */
-  ::-webkit-scrollbar-track {
-    display: none;
-  }
-  .text-container {
-    width: 100%;
-    overflow: hidden;
-    text-overflow: ellipsis;
+/* 隐藏整个滚动条 */
+::-webkit-scrollbar {
+  display: none;
+}
+
+/* 或者仅隐藏滚动条的轨道,保留滑块可操作性,但视觉上不显示滚动条 */
+/* ::-webkit-scrollbar-track {
+  display: none;
+} */
+
+.text-container {
+  width: 100%;
+  overflow: hidden;
+  text-overflow: ellipsis;
   }
 </style>

+ 12 - 8
src/views/order/index.vue

@@ -1,8 +1,8 @@
 <!-- 代码已包含 CSS:使用 TailwindCSS , 安装 TailwindCSS 后方可看到布局样式效果 -->
 
 <template>
-  <div class=" bg-gray-50 p-8 bg-white">
-    <div class="mx-auto w-full">
+  <div class=" bg-gray-50 box-border p-8 bg-white h-full ">
+    <div class="mx-auto h-full w-full flex flex-col">
       <!-- Search Area -->
       <div class="mb-6 flex items-center gap-4">
         <el-input v-model="searchKeyword" placeholder="Enter Keywords To Search" class="!rounded-button">
@@ -31,7 +31,8 @@
 
       <!-- Table -->
       <!-- 内容居中 -->
-      <el-table :data="tableData" class="w-full" :cell-style="{ textAlign: 'center' }"
+      <Empty v-if="tableData.length==0" class="flex-1" img="/src/assets/img/orderList/暂无支付记录.svg" text="No order information available at the moment"></Empty>
+      <el-table v-else :data="tableData" class="w-full flex-1 " :cell-style="{ textAlign: 'center'}"
         :header-cell-style="{ textAlign: 'center' }">
         <el-table-column prop="orderNumber" label="Order Number" width="120" />
         <el-table-column prop="employeeId" label="Employee ID" width="120" />
@@ -52,14 +53,13 @@
           </template>
         </el-table-column>
       </el-table>
-
-
-    </div>
-    <!-- Pagination -->
-    <div class="fixed bottom-5 right-5 flex items-center justify-between">
+    <div class="flex items-center justify-end mt-2">
       <el-pagination v-model:current-page="currentPage" v-model:page-size="pageSize" :page-sizes="[10, 20, 30, 40, 50]"
         :total="total" layout="prev, pager, next, sizes" />
     </div>
+
+    </div>
+
   </div>
 </template>
 
@@ -67,6 +67,7 @@
 import { ref } from 'vue';
 import { Search } from '@element-plus/icons-vue';
 import { useRouter } from 'vue-router';
+import Empty from '@/components/noProduct.vue';
 const router = useRouter();
 
 const searchKeyword = ref('');
@@ -166,4 +167,7 @@ const handleDetails = (row) => {
   --el-color-info:white;
   --el-input-border-color:#f67f20;
 }
+:deep(.el-table .cell){
+  white-space: nowrap;
+}
 </style>