13 Commits db423f451c ... 1ef098a96b

Author SHA1 Message Date
  陈雪 1ef098a96b Merge branch 'cx_dev' 1 day ago
  陈雪 5829556374 Merge remote-tracking branch 'origin/lyz_dev' 1 day ago
  Mcal 99f3290d12 ✨ feat(Payment): 添加支付抽屉组件,优化订单支付流程 1 day ago
  陈雪 5f79ff54fc ✨ feat(database): 添加店铺相关表结构,包括区域、材料、订单和桌子模型,并更新菜单相关模型以支持反序列化 1 day ago
  陈雪 af4e99a228 ✨ refactor(database): 更新菜单、商品、SKU、订单及区域表结构,确保字段为非空并设置默认值 1 day ago
  陈雪 b8db501cc3 ✨ fix(database): 修正菜单分类表的外键引用,改为引用 store_area 表 1 day ago
  陈雪 ec3211c2a0 ✨ refactor(database): 移除订单表中的物流信息字段 1 day ago
  陈雪 cdbd0b2ad8 ✨ feat(database): 更新 README 文档,添加材料管理和区域管理,新增店铺相关表结构及更新时间触发器 1 day ago
  Mcal 0b65092fed Merge branch 'wl_dev' of http://1.94.207.143:3000/chongqing/store-project into lyz_dev 1 day ago
  陈雪 0554e3b28a ✨ docs(README): 更新文档,添加盼达点餐系统的功能概述和数据库操作说明 1 day ago
  陈雪 bec05dc158 ✨ refactor(commands): 将 CommandResult 重命名为 CmdResult,以简化代码 2 days ago
  陈雪 adbd1bfcae ✨ feat(database): 更新菜单分类和商品表的创建时间和更新时间字段,添加更新时间触发器 2 days ago
  陈雪 ac4cdea01b ✨ feat(category): 重构分类服务,添加获取所有分类的方法并在菜单视图中调用 2 days ago

+ 25 - 4
README.md

@@ -1,7 +1,28 @@
-# Tauri + Vue 3
+# 盼达点餐系统
 
-This template should help get you started developing with Tauri + Vue 3 in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
+## 数据库操作
 
-## Recommended IDE Setup
+1. 菜品信息
+   1. 菜品分类
+   2. 菜品粗略信息
+   3. sku 信息
+   4. 规格信息
+2. 桌子管理
+   1. 区域管理
+   2. 桌号管理
+3. 订单管理
+   1. 创建订单
+   2. 订单同步
+4. 材料管理
 
-- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) + [Tauri](https://marketplace.visualstudio.com/items?itemName=tauri-apps.tauri-vscode) + [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer)
+## 数据同步
+
+1. 二维码展示&扫码
+2. 服务端 API
+   1. 获取分类
+   2. 获取商品
+   3. 订单创建
+   4. 桌子状态
+      1. 添加挂单
+      2. 追加菜品
+      3. 取消挂单/结账

+ 155 - 37
src-tauri/resources/table_struct.sql

@@ -2,43 +2,32 @@
 CREATE TABLE
     menu_cate (
         id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, -- 主键
-        name TEXT DEFAULT '', -- 分类名称
-        logo TEXT DEFAULT '', -- 分类Logo
-        local_logo TEXT DEFAULT '', -- 本地Logo路径
+        name TEXT NOT NULL DEFAULT '', -- 分类名称
+        logo TEXT NOT NULL DEFAULT '', -- 分类Logo
         description TEXT, -- 分类描述
-        create_time DATETIME DEFAULT NULL, -- 创建时间
-        update_time DATETIME DEFAULT NULL, -- 更新时间
-        sort INTEGER DEFAULT 0, -- 排序
-        status TEXT DEFAULT 'A' -- 状态 (A-Active, D-Deleted)
+        create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
+        update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 更新时间
+        sort INTEGER NOT NULL DEFAULT 0, -- 排序
+        status INTEGER NOT NULL DEFAULT 1 -- 状态 (1-Active, 0-Inactive)
     );
 
 -- 创建商品表
 CREATE TABLE
     menu_commodity (
         id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, -- 主键
-        type TEXT DEFAULT 'product', -- 商品类型
-        name TEXT DEFAULT '', -- 商品名称
-        cate_id INTEGER DEFAULT 0, -- 分类ID
-        goods_no TEXT DEFAULT '', -- 商品编号
-        is_single_spec TEXT DEFAULT 'Y', -- 是否单规格 (Y-Yes, N-No)
-        logo TEXT DEFAULT '', -- 商品Logo
-        images TEXT DEFAULT '', -- 商品图片
-        price REAL DEFAULT 0.00, -- 价格
-        line_price REAL DEFAULT 0.00, -- 划线价
-        stock INTEGER DEFAULT 0, -- 库存
-        weight REAL DEFAULT 0.00, -- 重量
-        coupon_ids TEXT DEFAULT '', -- 优惠券ID
-        service_time INTEGER DEFAULT 0, -- 服务时间
-        init_sale INTEGER DEFAULT 0, -- 初始销量
-        sale_point TEXT DEFAULT '', -- 卖点
-        can_use_point TEXT DEFAULT 'N', -- 是否可用积分 (Y-Yes, N-No)
-        is_member_discount TEXT DEFAULT 'Y', -- 是否会员折扣 (Y-Yes, N-No)
-        sort INTEGER DEFAULT 0, -- 排序
-        description TEXT, -- 商品描述
-        create_time DATETIME DEFAULT NULL, -- 创建时间
-        update_time DATETIME DEFAULT NULL, -- 更新时间
-        operator TEXT DEFAULT NULL, -- 操作员
-        status TEXT DEFAULT 'A', -- 状态 (A-Active, D-Deleted)
+        name TEXT NOT NULL DEFAULT '', -- 商品名称
+        cate_id INTEGER NOT NULL DEFAULT 0, -- 分类ID
+        goods_no TEXT NOT NULL DEFAULT '', -- 商品编号
+        is_single_spec INTEGER NOT NULL DEFAULT 1, -- 是否单规格 (1-单规格, 0-多规格)
+        logo TEXT NOT NULL DEFAULT '', -- 商品Logo
+        price REAL NOT NULL DEFAULT 0.00, -- 价格
+        line_price REAL NOT NULL DEFAULT 0.00, -- 商品原价
+        stock INTEGER NOT NULL DEFAULT 0, -- 库存
+        sort INTEGER NOT NULL DEFAULT 0, -- 排序
+        description TEXT NOT NULL DEFAULT '', -- 商品描述
+        create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
+        update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 更新时间
+        status INTEGER NOT NULL DEFAULT 1, -- 状态 (1-Active, 0-Inactive),
         FOREIGN KEY (cate_id) REFERENCES menu_cate (id)
     );
 
@@ -46,14 +35,13 @@ CREATE TABLE
 CREATE TABLE
     menu_sku (
         id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, -- 主键
-        sku_no TEXT DEFAULT '', -- SKU编号
-        logo TEXT DEFAULT '', -- SKU Logo
+        sku_no TEXT NOT NULL DEFAULT '', -- SKU编号
+        logo TEXT NOT NULL DEFAULT '', -- SKU Logo
         goods_id INTEGER NOT NULL DEFAULT 0, -- 商品ID
         stock INTEGER NOT NULL DEFAULT 0, -- 库存
         price REAL NOT NULL DEFAULT 0.00, -- 价格
-        line_price REAL NOT NULL DEFAULT 0.00, -- 划线价
-        weight REAL DEFAULT 0.00, -- 重量
-        status TEXT NOT NULL DEFAULT 'A', -- 状态 (A-Active, D-Deleted)
+        line_price REAL NOT NULL DEFAULT 0.00, -- 商品原价
+        status INTEGER NOT NULL DEFAULT 1, -- 状态 (1-Active, 0-Inactive),
         FOREIGN KEY (goods_id) REFERENCES menu_commodity (id)
     );
 
@@ -64,7 +52,7 @@ CREATE TABLE
         goods_id INTEGER NOT NULL DEFAULT 0, -- 商品ID
         name TEXT NOT NULL DEFAULT '', -- 规格名称
         value TEXT NOT NULL DEFAULT '', -- 规格值
-        status TEXT DEFAULT 'A', -- 状态 (A-Active, D-Deleted)
+        status INTEGER NOT NULL DEFAULT 1, -- 状态 (1-Active, 0-Inactive),
         FOREIGN KEY (goods_id) REFERENCES menu_commodity (id)
     );
 
@@ -76,4 +64,134 @@ CREATE TABLE
         PRIMARY KEY (sku_id, spec_id),
         FOREIGN KEY (sku_id) REFERENCES menu_sku (id),
         FOREIGN KEY (spec_id) REFERENCES menu_spec (id)
-    );
+    );
+
+-- 创建店铺订单表信息
+CREATE TABLE
+    store_order (
+        id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, -- 自增ID
+        order_sn TEXT NOT NULL DEFAULT '', -- 订单号
+        table_id INTEGER NOT NULL, -- 所属桌码ID
+        pay_type INTEGER NOT NULL DEFAULT 0, -- 支付方式 (1-现金, 0-Paypal)
+        amount REAL NOT NULL DEFAULT 0.00, -- 订单金额
+        pay_amount REAL NOT NULL DEFAULT 0.00, -- 支付金额
+        discount REAL NOT NULL DEFAULT 0.00, -- 折扣金额
+        param TEXT NOT NULL DEFAULT '', -- 订单参数
+        service_fee REAL DEFAULT NULL, -- 服务费
+        remark TEXT NOT NULL DEFAULT '', -- 用户备注
+        create_time DATETIME DEFAULT NULL, -- 创建时间
+        update_time DATETIME DEFAULT NULL, -- 更新时间
+        status TEXT NOT NULL DEFAULT 'A', -- 订单状态
+        pay_time DATETIME DEFAULT NULL, -- 支付时间
+        pay_status INTEGER NOT NULL DEFAULT 1, -- 支付状态
+        settle_status INTEGER NOT NULL DEFAULT 1, -- 结算状态
+        goods TEXT NOT NULL DEFAULT '{}' -- 订单商品信息
+    );
+
+-- 创建店铺材料表信息
+CREATE TABLE
+    store_material (
+        id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, -- 材料表id
+        material_no TEXT NOT NULL, -- 材料编号
+        material_type TEXT NOT NULL, -- 材料类别
+        name TEXT NOT NULL, -- 材料名称
+        specification TEXT NOT NULL, -- 规格
+        inventory INTEGER NOT NULL DEFAULT 0, -- 库存数量
+        shelf_life INTEGER NOT NULL DEFAULT 0, -- 保质期
+        unit TEXT NOT NULL, -- 单位
+        img TEXT NOT NULL, -- 材料文件/图片id
+        purchase_period INTEGER NOT NULL DEFAULT 0, -- 采购期数
+        create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
+        update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 更新时间
+        status INTEGER NOT NULL DEFAULT 1 -- 状态0下架1上架
+    );
+
+-- 店铺区域表
+CREATE TABLE
+    store_area (
+        id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, -- 区域id
+        name TEXT NOT NULL, -- 区域名称
+        description TEXT NOT NULL DEFAULT '', -- 区域描述
+        create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
+        update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 更新时间
+        status INTEGER NOT NULL DEFAULT 1 -- 状态 (1-有效, 0-无效)
+    );
+
+-- 店铺座位表
+CREATE TABLE
+    store_table (
+        id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, -- 桌子id
+        area_id INTEGER NOT NULL, -- 所属区域id
+        table_no TEXT NOT NULL, -- 桌号
+        capacity INTEGER NOT NULL DEFAULT 0, -- 座位数
+        create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
+        update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 更新时间
+        status INTEGER NOT NULL DEFAULT 1, -- 状态 (1-有效, 0-无效)
+        FOREIGN KEY (area_id) REFERENCES store_area (id)
+    );
+
+-- 新增菜单分类表的更新时间触发器
+CREATE TRIGGER trg_menu_cate_update_time AFTER
+UPDATE ON menu_cate FOR EACH ROW WHEN NEW.update_time = OLD.update_time BEGIN
+UPDATE menu_cate
+SET
+    update_time = CURRENT_TIMESTAMP
+WHERE
+    id = OLD.id;
+
+END;
+
+-- 新增商品表的更新时间触发器
+CREATE TRIGGER trg_menu_commodity_update_time AFTER
+UPDATE ON menu_commodity FOR EACH ROW WHEN NEW.update_time = OLD.update_time BEGIN
+UPDATE menu_commodity
+SET
+    update_time = CURRENT_TIMESTAMP
+WHERE
+    id = OLD.id;
+
+END;
+
+-- 新增订单表的更新时间触发器
+CREATE TRIGGER trg_order_update_time AFTER
+UPDATE ON store_order FOR EACH ROW WHEN NEW.update_time = OLD.update_time BEGIN
+UPDATE store_order
+SET
+    update_time = CURRENT_TIMESTAMP
+WHERE
+    id = OLD.id;
+
+END;
+
+-- 新增材料表的更新时间触发器
+CREATE TRIGGER trg_material_update_time AFTER
+UPDATE ON store_material FOR EACH ROW WHEN NEW.update_time = OLD.update_time BEGIN
+UPDATE store_material
+SET
+    update_time = CURRENT_TIMESTAMP
+WHERE
+    id = OLD.id;
+
+END;
+
+-- 新增区域表的更新时间触发器
+CREATE TRIGGER trg_area_update_time AFTER
+UPDATE ON store_area FOR EACH ROW WHEN NEW.update_time = OLD.update_time BEGIN
+UPDATE store_area
+SET
+    update_time = CURRENT_TIMESTAMP
+WHERE
+    id = OLD.id;
+
+END;
+
+-- 新增桌子表的更新时间触发器
+CREATE TRIGGER trg_table_update_time AFTER
+UPDATE ON store_table FOR EACH ROW WHEN NEW.update_time = OLD.update_time BEGIN
+UPDATE store_table
+SET
+    update_time = CURRENT_TIMESTAMP
+WHERE
+    id = OLD.id;
+
+END;

+ 2 - 2
src-tauri/src/commands/mod.rs

@@ -1,12 +1,12 @@
 use tauri::State;
 
 use crate::{
-    AppState, CommandResult,
+    AppState, CmdResult,
     service::category::{Category, CategoryWithSpu},
 };
 
 #[tauri::command]
-pub async fn get_category(app_state: State<'_, AppState>) -> CommandResult<Vec<CategoryWithSpu>> {
+pub async fn get_category(app_state: State<'_, AppState>) -> CmdResult<Vec<CategoryWithSpu>> {
     let category = Category::new(app_state.conn.clone());
     let categories = category.get_category_commodity().await;
     match categories {

+ 1 - 1
src-tauri/src/lib.rs

@@ -7,7 +7,7 @@ use std::fs::{self, File};
 use std::sync::Arc;
 use tauri::{AppHandle, Manager, path::BaseDirectory};
 
-type CommandResult<T> = Result<T, String>;
+type CmdResult<T> = Result<T, String>;
 // 添加 AppState 结构体
 #[derive(Default)]
 pub struct AppState {

+ 3 - 6
src-tauri/src/models/menu_cate.rs

@@ -1,9 +1,9 @@
 //! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0
 
 use sea_orm::entity::prelude::*;
-use serde::Serialize;
+use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[sea_orm(table_name = "menu_cate")]
 pub struct Model {
     #[sea_orm(primary_key)]
@@ -13,16 +13,13 @@ pub struct Model {
     #[sea_orm(column_type = "Text", nullable)]
     pub logo: Option<String>,
     #[sea_orm(column_type = "Text", nullable)]
-    pub local_logo: Option<String>,
-    #[sea_orm(column_type = "Text", nullable)]
     pub description: Option<String>,
     #[sea_orm(column_type = "custom(\"DATETIME\")", nullable)]
     pub create_time: Option<String>,
     #[sea_orm(column_type = "custom(\"DATETIME\")", nullable)]
     pub update_time: Option<String>,
     pub sort: Option<i32>,
-    #[sea_orm(column_type = "Text", nullable)]
-    pub status: Option<String>,
+    pub status: Option<i32>,
 }
 
 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]

+ 4 - 23
src-tauri/src/models/menu_commodity.rs

@@ -1,40 +1,24 @@
 //! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0
 
 use sea_orm::entity::prelude::*;
-use serde::Serialize;
+use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[sea_orm(table_name = "menu_commodity")]
 pub struct Model {
     #[sea_orm(primary_key)]
     pub id: i32,
     #[sea_orm(column_type = "Text", nullable)]
-    pub r#type: Option<String>,
-    #[sea_orm(column_type = "Text", nullable)]
     pub name: Option<String>,
     pub cate_id: Option<i32>,
     #[sea_orm(column_type = "Text", nullable)]
     pub goods_no: Option<String>,
-    #[sea_orm(column_type = "Text", nullable)]
-    pub is_single_spec: Option<String>,
+    pub is_single_spec: Option<i32>,
     #[sea_orm(column_type = "Text", nullable)]
     pub logo: Option<String>,
-    #[sea_orm(column_type = "Text", nullable)]
-    pub images: Option<String>,
     pub price: Option<Decimal>,
     pub line_price: Option<Decimal>,
     pub stock: Option<i32>,
-    pub weight: Option<Decimal>,
-    #[sea_orm(column_type = "Text", nullable)]
-    pub coupon_ids: Option<String>,
-    pub service_time: Option<i32>,
-    pub init_sale: Option<i32>,
-    #[sea_orm(column_type = "Text", nullable)]
-    pub sale_point: Option<String>,
-    #[sea_orm(column_type = "Text", nullable)]
-    pub can_use_point: Option<String>,
-    #[sea_orm(column_type = "Text", nullable)]
-    pub is_member_discount: Option<String>,
     pub sort: Option<i32>,
     #[sea_orm(column_type = "Text", nullable)]
     pub description: Option<String>,
@@ -42,10 +26,7 @@ pub struct Model {
     pub create_time: Option<String>,
     #[sea_orm(column_type = "custom(\"DATETIME\")", nullable)]
     pub update_time: Option<String>,
-    #[sea_orm(column_type = "Text", nullable)]
-    pub operator: Option<String>,
-    #[sea_orm(column_type = "Text", nullable)]
-    pub status: Option<String>,
+    pub status: Option<i32>,
 }
 
 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]

+ 3 - 4
src-tauri/src/models/menu_sku.rs

@@ -1,8 +1,9 @@
 //! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0
 
 use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Deserialize, Serialize)]
 #[sea_orm(table_name = "menu_sku")]
 pub struct Model {
     #[sea_orm(primary_key)]
@@ -15,9 +16,7 @@ pub struct Model {
     pub stock: i32,
     pub price: Decimal,
     pub line_price: Decimal,
-    pub weight: Option<Decimal>,
-    #[sea_orm(column_type = "Text")]
-    pub status: String,
+    pub status: Option<i32>,
 }
 
 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]

+ 3 - 3
src-tauri/src/models/menu_sku_spec.rs

@@ -1,9 +1,9 @@
 //! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0
 
 use sea_orm::entity::prelude::*;
-use serde::Serialize;
+use serde::{Deserialize, Serialize};
 
-#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[sea_orm(table_name = "menu_sku_spec")]
 pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
@@ -12,7 +12,7 @@ pub struct Model {
     pub spec_id: i32,
 }
 
-#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation, Serialize)]
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
 pub enum Relation {
     #[sea_orm(
         belongs_to = "super::menu_sku::Entity",

+ 1 - 2
src-tauri/src/models/menu_spec.rs

@@ -13,8 +13,7 @@ pub struct Model {
     pub name: String,
     #[sea_orm(column_type = "Text")]
     pub value: String,
-    #[sea_orm(column_type = "Text", nullable)]
-    pub status: Option<String>,
+    pub status: Option<i32>,
 }
 
 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]

+ 4 - 0
src-tauri/src/models/mod.rs

@@ -7,3 +7,7 @@ pub mod menu_commodity;
 pub mod menu_sku;
 pub mod menu_sku_spec;
 pub mod menu_spec;
+pub mod store_area;
+pub mod store_material;
+pub mod store_order;
+pub mod store_table;

+ 7 - 3
src-tauri/src/models/prelude.rs

@@ -2,6 +2,10 @@
 
 pub use super::menu_cate::Entity as MenuCate;
 pub use super::menu_commodity::Entity as MenuCommodity;
-// pub use super::menu_sku::Entity as MenuSku;
-// pub use super::menu_sku_spec::Entity as MenuSkuSpec;
-// pub use super::menu_spec::Entity as MenuSpec;
+pub use super::menu_sku::Entity as MenuSku;
+pub use super::menu_sku_spec::Entity as MenuSkuSpec;
+pub use super::menu_spec::Entity as MenuSpec;
+pub use super::store_area::Entity as StoreArea;
+pub use super::store_material::Entity as StoreMaterial;
+pub use super::store_order::Entity as StoreOrder;
+pub use super::store_table::Entity as StoreTable;

+ 34 - 0
src-tauri/src/models/store_area.rs

@@ -0,0 +1,34 @@
+//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "store_area")]
+pub struct Model {
+    #[sea_orm(primary_key)]
+    pub id: i32,
+    #[sea_orm(column_type = "Text")]
+    pub name: String,
+    #[sea_orm(column_type = "Text", nullable)]
+    pub description: Option<String>,
+    #[sea_orm(column_type = "custom(\"DATETIME\")", nullable)]
+    pub create_time: Option<String>,
+    #[sea_orm(column_type = "custom(\"DATETIME\")", nullable)]
+    pub update_time: Option<String>,
+    pub status: Option<i32>,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(has_many = "super::store_table::Entity")]
+    StoreTable,
+}
+
+impl Related<super::store_table::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::StoreTable.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}

+ 36 - 0
src-tauri/src/models/store_material.rs

@@ -0,0 +1,36 @@
+//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "store_material")]
+pub struct Model {
+    #[sea_orm(primary_key)]
+    pub id: i32,
+    #[sea_orm(column_type = "Text")]
+    pub material_no: String,
+    #[sea_orm(column_type = "Text")]
+    pub material_type: String,
+    #[sea_orm(column_type = "Text")]
+    pub name: String,
+    #[sea_orm(column_type = "Text")]
+    pub specification: String,
+    pub inventory: i32,
+    pub shelf_life: i32,
+    #[sea_orm(column_type = "Text")]
+    pub unit: String,
+    #[sea_orm(column_type = "Text")]
+    pub img: String,
+    pub purchase_period: Option<i32>,
+    #[sea_orm(column_type = "custom(\"DATETIME\")", nullable)]
+    pub create_time: Option<String>,
+    #[sea_orm(column_type = "custom(\"DATETIME\")", nullable)]
+    pub update_time: Option<String>,
+    pub status: Option<i32>,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {}
+
+impl ActiveModelBehavior for ActiveModel {}

+ 40 - 0
src-tauri/src/models/store_order.rs

@@ -0,0 +1,40 @@
+//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "store_order")]
+pub struct Model {
+    #[sea_orm(primary_key)]
+    pub id: i32,
+    #[sea_orm(column_type = "Text")]
+    pub order_sn: String,
+    pub table_id: i32,
+    pub pay_type: i32,
+    pub amount: Option<Decimal>,
+    pub pay_amount: Option<Decimal>,
+    pub discount: Option<Decimal>,
+    #[sea_orm(column_type = "Text", nullable)]
+    pub param: Option<String>,
+    pub service_fee: Option<Decimal>,
+    #[sea_orm(column_type = "Text", nullable)]
+    pub remark: Option<String>,
+    #[sea_orm(column_type = "custom(\"DATETIME\")", nullable)]
+    pub create_time: Option<String>,
+    #[sea_orm(column_type = "custom(\"DATETIME\")", nullable)]
+    pub update_time: Option<String>,
+    #[sea_orm(column_type = "Text", nullable)]
+    pub status: Option<String>,
+    #[sea_orm(column_type = "custom(\"DATETIME\")", nullable)]
+    pub pay_time: Option<String>,
+    pub pay_status: Option<i32>,
+    pub settle_status: Option<i32>,
+    #[sea_orm(column_type = "Text", nullable)]
+    pub goods: Option<String>,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {}
+
+impl ActiveModelBehavior for ActiveModel {}

+ 40 - 0
src-tauri/src/models/store_table.rs

@@ -0,0 +1,40 @@
+//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0
+
+use sea_orm::entity::prelude::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
+#[sea_orm(table_name = "store_table")]
+pub struct Model {
+    #[sea_orm(primary_key)]
+    pub id: i32,
+    pub area_id: i32,
+    #[sea_orm(column_type = "Text")]
+    pub table_no: String,
+    pub capacity: Option<i32>,
+    #[sea_orm(column_type = "custom(\"DATETIME\")", nullable)]
+    pub create_time: Option<String>,
+    #[sea_orm(column_type = "custom(\"DATETIME\")", nullable)]
+    pub update_time: Option<String>,
+    pub status: Option<i32>,
+}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {
+    #[sea_orm(
+        belongs_to = "super::store_area::Entity",
+        from = "Column::AreaId",
+        to = "super::store_area::Column::Id",
+        on_update = "NoAction",
+        on_delete = "NoAction"
+    )]
+    StoreArea,
+}
+
+impl Related<super::store_area::Entity> for Entity {
+    fn to() -> RelationDef {
+        Relation::StoreArea.def()
+    }
+}
+
+impl ActiveModelBehavior for ActiveModel {}

+ 7 - 2
src/service/CategoryService.ts

@@ -1,5 +1,10 @@
 import { MenuCategory } from '@/interface/MenuCate'
+import { invoke } from '@tauri-apps/api/core'
 
-export async function getMenuCategories() {
-  return []
+export class CategoryService {
+  static async getAll() {
+    const categories = await invoke<MenuCategory>('get_category')
+    console.log('categories: ', categories)
+    return categories
+  }
 }

+ 112 - 0
src/views/menu/components/pay-drawer.vue

@@ -0,0 +1,112 @@
+<template>
+    <div>
+        <!-- 触发抽屉的按钮,这里简单示例 -->
+        <el-drawer v-model="show" :show-close="false" direction="rtl" size="60%">
+            <div class="grid grid-cols-2 h-screen">
+                <div class="border-r border-gray-100 mr-5 h-full flex flex-col">
+                    <h3 class="p-3 text-2xl ">Confirmation</h3>
+                    <order type="pay" class="h-[calc(100vh-60px)]" ></order>
+                </div>
+                <div class="bg-white rounded-lg pr-5 flex flex-col h-full">
+                    <div class="flex-1">
+                        <div class="mb-8">
+                            <h1 class="text-2xl font-semibold mb-1">A1-Payment</h1>
+                            <p class="text-gray-500 text-sm">3 Payment Methods Available</p>
+                        </div>
+
+                        <div class="space-y-4 mb-8">
+                            <div class="flex justify-between items-center">
+                                <span class="text-gray-600">Service Charge</span>
+                                <span class="font-medium">$ 12.00</span>
+                            </div>
+                            <div class="flex justify-between items-center">
+                                <span class="text-gray-600">Sub Total</span>
+                                <span class="font-medium">$ 100.00</span>
+                            </div>
+                        </div>
+
+                        <div class="mb-8">
+                            <p class="text-gray-600 mb-4">Payment Method</p>
+                            <div class="grid grid-cols-3 gap-4">
+                                <button v-for="method in paymentMethods" :key="method.id"
+                                    @click="selectPaymentMethod(method.id)" :class="[
+                                        'flex flex-col items-center justify-center p-4 rounded-lg border transition-all duration-200 !rounded-button whitespace-nowrap',
+                                        selectedMethod === method.id ? 'border-orange-500 bg-orange-50' : 'border-gray-200 hover:border-orange-300'
+                                    ]">
+                                    <i
+                                        :class="['text-xl mb-2', method.icon, selectedMethod === method.id ? 'text-orange-500' : 'text-gray-400']"></i>
+                                    <span
+                                        :class="['text-sm', selectedMethod === method.id ? 'text-orange-500' : 'text-gray-600']">{{
+                                            method.name }}</span>
+                                </button>
+                            </div>
+                        </div>
+
+                        <div class="mb-12">
+                            <p class="text-gray-600 mb-4">Tip</p>
+                            <div class="flex items-center relative">
+                                <span class="text-gray-400 mr-2 absolute top-1/2 right-0 -translate-y-1/2">$</span>
+                                <input type="text" v-model="tipAmount"
+                                    class="w-full p-3 rounded-lg border-gray-200 border focus:border-orange-500 focus:ring-0 text-gray-700"
+                                    placeholder="Enter tip amount">
+                            </div>
+                        </div>
+                    </div>
+                    <div class="grid grid-cols-5 gap-3 mb-3 box-border ">
+                        <button
+                            class="col-span-2 px-6 py-3 border border-orange-500 text-orange-500 rounded-lg hover:bg-orange-50 transition-colors !rounded-button whitespace-nowrap">
+                            Registration
+                        </button>
+                        <button
+                            class="col-span-3 px-6 py-3 bg-orange-500 text-white rounded-lg hover:bg-orange-600 transition-colors !rounded-button whitespace-nowrap">
+                            Confirm Payment
+                        </button>
+                    </div>
+                </div>
+            </div>
+
+        </el-drawer>
+    </div>
+</template>
+
+<script setup>
+import { ref } from 'vue';
+import { ElDrawer } from 'element-plus';
+import order from './rightOrder/components/order.vue'
+
+const show = defineModel("show")
+const paymentMethods = [
+    { id: 1, name: 'Credit Card', icon: 'fas fa-credit-card' },
+    { id: 2, name: 'PayPal', icon: 'fab fa-paypal' },
+    { id: 3, name: 'Cash', icon: 'fas fa-money-bill' }
+];
+
+const selectedMethod = ref(1);
+const tipAmount = ref('');
+
+const selectPaymentMethod = (id) => {
+    selectedMethod.value = id;
+};
+</script>
+
+<style scoped>
+input[type="number"]::-webkit-inner-spin-button,
+input[type="number"]::-webkit-outer-spin-button {
+    -webkit-appearance: none;
+    margin: 0;
+}
+
+input[type="number"] {
+    -moz-appearance: textfield;
+}
+
+:deep(.el-drawer__header) {
+    margin: 0;
+    padding: 0;
+}
+
+:deep(.el-drawer__body) {
+    margin: 0;
+    padding: 0;
+}
+</style>

+ 8 - 4
src/views/menu/components/rightOrder/components/order.vue

@@ -48,13 +48,13 @@
           </div>
         </div>
 
-        <div class="border-t border-gray-100 pt-4">
-          <div class="mb-4">
+        <div class="border-t border-gray-100 pt-4" >
+          <div class="mb-4" v-show="type!='pay'">
             <h3 class="font-medium mb-2">Order Notes</h3>
             <p class="text-gray-600 text-sm">No Chili, No Cilantro</p>
           </div>
 
-          <div class="flex items-center justify-between pt-4 border-t border-gray-100">
+          <div class="flex items-center justify-between pt-4  border-gray-100">
             <span class="font-medium">Total</span>
             <span class="text-sm font-medium">${{ total.toFixed(2) }}</span>
           </div>
@@ -75,7 +75,11 @@ interface OrderItem {
   quantity: number
   image: string
 }
-
+const props = defineProps({
+  type:{
+    default:'detail'
+  }
+})
 const orderItems = ref<OrderItem[]>([
   {
     name: 'Spicy Seasoned Seafood',

+ 2 - 2
src/views/menu/components/rightOrder/rightOrder.vue

@@ -16,6 +16,7 @@
           Registration
         </button>
         <button
+          @click="emits('showPayDrawer')"
           class="rounded text-sm py-3 px-6 bg-white border border-gray-200 text-gray-700 !rounded-button whitespace-nowrap hover:bg-gray-50 transition-colors"
         >
           Kitchen Receipt
@@ -34,8 +35,7 @@
 <script lang="ts" setup>
 import noProduct from '@/components/noProduct.vue'
 import order from './components/order.vue'
-import { emit } from '@tauri-apps/api/event';
-const emits= defineEmits(['showDeskDrawer'])
+const emits= defineEmits(['showDeskDrawer','showPayDrawer'])
 
 </script>
 

+ 186 - 155
src/views/menu/index.vue

@@ -4,24 +4,37 @@
       <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
-              @click="handleArrow(-1)"
-                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 @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' : '' ]">
+                  <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
-              @click="handleArrow(1)"
-                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>
@@ -29,14 +42,25 @@
             </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,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
+              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>
@@ -47,159 +71,166 @@
       </div>
     </div>
     <div class="w-[500px] h-full overflow-hidden border-l border-gray-200">
-      <rightOrder @showDeskDrawer="catgroyClick"></rightOrder>
+      <rightOrder @showDeskDrawer="catgroyClick" @showPayDrawer="onPay"></rightOrder>
     </div>
     <OrderDrawer v-model:show="show" />
     <deskDrawer v-model:show="deskShow" />
-
+    <payDrawer v-model:show="payShow" />
   </div>
 </template>
-<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)
-
-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 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 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'
+  import payDrawer from './components/pay-drawer.vue'
+  const { t } = useI18n()
+
+  const show = ref(false)
+
+  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 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)
+  }
+
+  //pay
+  const payShow = ref(false)
+  const onPay = () => {
+    payShow.value = true
+  }
 </script>
 <style scoped>
-.active {
-  background-color: #f67f20;
-  color:white;
-  border-radius: 5px;
-}
-::-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 {
+    display: none;
+  }
 
-/* 或者仅隐藏滚动条的轨道,保留滑块可操作性,但视觉上不显示滚动条 */
-/* ::-webkit-scrollbar-track {
+  /* 或者仅隐藏滚动条的轨道,保留滑块可操作性,但视觉上不显示滚动条 */
+  /* ::-webkit-scrollbar-track {
   display: none;
 } */
 
-.text-container {
-  width: 100%;
-  overflow: hidden;
-  text-overflow: ellipsis;
+  .text-container {
+    width: 100%;
+    overflow: hidden;
+    text-overflow: ellipsis;
   }
 </style>