新闻详情

新闻详情

首页 / 资讯中心 / 详情

SpringBoot + Vue3 + 小程序:珠宝电商商城全栈开发实战拆解

发布时间:2026/9/4 17:45:42来源:尧图网络
SpringBoot + Vue3 + 小程序:珠宝电商商城全栈开发实战拆解
最近在做珠宝首饰类目的电商小程序时你会发现这类项目比普通标品商城更考验建模和订单设计。珠宝商品往往是“同款不同规格”比如一款黄金手镯可能同时存在 52、54、56 等不同手寸每个手寸的库存、价格还可能不同再加上 C 端小程序、商家后台管理系统要同时维护商品、SKU、订单和支付整个项目非常适合用来做 SpringBoot 全家桶 Vue3 小程序的全栈实战。这篇文章我会围绕一套“珠宝首饰交易小程序 珠宝首饰电商平台后台”的业务模型从数据库设计到后端接口再到 Vue3 管理后台和小程序端实现完整拆解一套可运行的商城项目方案。项目标题里出现的 SpringBoot4更像是课程或模板里的编号。实际动手开发时建议直接使用你创建 Spring Boot 工程时能获取的最新稳定版本目前常见的还是 3.x 路线。下文代码统一按 Spring Boot 工程风格编写版本只需要在创建工程时保持一致即可。如果你是准备做毕业设计、全栈练手项目或者想把“商品 - SKU - 库存 - 订单 - 支付”这条电商主线吃透这篇文章可以直接作为开发参考。1. 珠宝首饰商城项目的特点与技术选型1.1 这个系统和普通商城有什么区别很多电商初学者会先做一个“通用商城”例如服装、数码或图书类商品。这类项目通常是简单的“商品主表 订单表 购物车表”商品只有一个价格和一套库存下单逻辑比较容易。但珠宝首饰交易场景有几个明显差异同一款产品可能存在多种规格例如材质、手寸、克重、链长、款式等。商品价格往往随规格浮动例如 20 克金镯和 30 克金镯价格不同。用户需要查看更多信任信息例如证书编号、成色、质检图、主石参数。后台运营要管理上下架、库存、推荐位、首页轮播等多类数据。交易链路涉及微信登录、收货地址、订单、模拟支付或微信支付安全要求更高。所以设计珠宝商城项目时不能只在商品表上加几个字段就完事而是要引入“商品 SPU 商品 SKU”的建模思路。简单的理解方式就是SPU商品例如“黄金古法手镯-繁花系列”。SKU具体可下单的规格例如“繁花系列 54 号手寸 约 25.8 克”。这一层建模是珠宝商城项目最先要解决的问题。1.2 技术栈分工整个项目可以分成三端端技术栈主要职责后端接口服务Spring Boot、MyBatis-Plus、MySQL、Redis登录鉴权、商品、购物车、订单、支付回调商家/管理后台Vue3、Vite、Element Plus、Pinia、Vue Router商品管理、订单处理、数据看板用户小程序uni-app Vue3 组合式 API或微信原生小程序浏览商品、加入购物车、下单支付选择 Vue3 的主要原因在于组合式 API 在业务状态多、页面复用的场景下更清晰。尤其是管理后台的商品编辑器和订单列表逻辑代码比 Vue2 时代更容易维护。小程序端这里给出一个选择建议如果只发布微信小程序可以使用微信原生开发控制更细。如果以后还想发布到支付宝小程序、抖音小程序或 H5可以使用 uni-app Vue3。下文小程序端示例以 uni-app Vue3 组合式 API 为主。因为后台管理系统已经是 Vue3前端知识可以复用学习成本不会太高。2. 从数据模型开始设计珠宝商城2.1 核心模块划分一个珠宝首饰电商平台可以按角色拆成三大块C 端用户可见的功能首页轮播、推荐位、分类入口。商品分类列表、搜索、商品详情、SKU 选择。购物车加入购物车、修改数量、结算。订单提交订单、订单列表、支付、确认收货。商家/管理员功能商品管理新增商品、维护规格、上下架。类目管理一级/二级分类。订单管理查看订单、发货。用户管理查看用户列表和基本状态。营销和首页配置轮播图、推荐商品。后端服务要支撑以上功能并提供统一的登录鉴权、接口返回结构和异常处理。2.2 数据库表规划根据上面的功能至少要设计以下核心表t_admin_user 管理员表 t_user 用户表 t_category 商品分类表 t_goods 商品 SPU 表 t_goods_sku SKU 库存价格表 t_cart 购物车表 t_user_address 收货地址表 t_order 订单主表 t_order_item 订单明细表 t_pay_record 支付流水表 t_banner 首页轮播表实际开发时还可能增加预售、优惠券、售后、运费模板等表。项目初期不需要一步到位但建议把“商品 - SKU - 订单 - 明细”这几张表设计规范。为了便于演示我按 MySQL 数据库写一套简化的初始化 SQL。注意实际项目请使用自己的数据库名称并在执行建表语句前确认当前环境是可测试的环境。-- 用户表 CREATE TABLE t_user ( id bigint NOT NULL AUTO_INCREMENT, openid varchar(64) NOT NULL COMMENT 小程序openid, nickname varchar(64) DEFAULT COMMENT 昵称, avatar varchar(500) DEFAULT COMMENT 头像, phone varchar(20) DEFAULT COMMENT 手机号, status tinyint NOT NULL DEFAULT 1 COMMENT 1正常 0禁用, create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_openid (openid) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户表; -- 分类表 CREATE TABLE t_category ( id bigint NOT NULL AUTO_INCREMENT, name varchar(64) NOT NULL COMMENT 分类名称, parent_id bigint NOT NULL DEFAULT 0 COMMENT 父分类id, sort int NOT NULL DEFAULT 0 COMMENT 排序, status tinyint NOT NULL DEFAULT 1 COMMENT 1显示 0隐藏, create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT商品分类表; -- 商品表 SPU CREATE TABLE t_goods ( id bigint NOT NULL AUTO_INCREMENT, name varchar(128) NOT NULL COMMENT 商品名称, subtitle varchar(255) DEFAULT COMMENT 副标题, category_id bigint NOT NULL COMMENT 分类id, main_image varchar(500) DEFAULT COMMENT 主图, detail_images text COMMENT 详情图多个使用逗号分隔, material varchar(32) DEFAULT COMMENT 材质如黄金/铂金/银/翡翠, cert_no varchar(64) DEFAULT COMMENT 证书编号, status tinyint NOT NULL DEFAULT 1 COMMENT 1上架 0下架, sort int NOT NULL DEFAULT 0 COMMENT 排序权重, sales int NOT NULL DEFAULT 0 COMMENT 销量, create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_category (category_id), KEY idx_status (status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT商品表; -- 商品 SKU 表 CREATE TABLE t_goods_sku ( id bigint NOT NULL AUTO_INCREMENT, goods_id bigint NOT NULL COMMENT 商品id, sku_name varchar(128) NOT NULL COMMENT 规格名称如 54号/25.8g, price decimal(12,2) NOT NULL COMMENT 售价, market_price decimal(12,2) DEFAULT NULL COMMENT 市场价/划线价, stock int NOT NULL DEFAULT 0 COMMENT 库存, image varchar(500) DEFAULT COMMENT 规格图, status tinyint NOT NULL DEFAULT 1 COMMENT 1启用 0停用, create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_goods (goods_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT商品SKU表; -- 购物车表 CREATE TABLE t_cart ( id bigint NOT NULL AUTO_INCREMENT, user_id bigint NOT NULL, sku_id bigint NOT NULL, goods_id bigint NOT NULL, count int NOT NULL DEFAULT 1 COMMENT 数量, checked tinyint NOT NULL DEFAULT 1 COMMENT 是否勾选, create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_user_sku (user_id,sku_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT购物车表; -- 订单主表 CREATE TABLE t_order ( id bigint NOT NULL AUTO_INCREMENT, order_no varchar(64) NOT NULL COMMENT 订单号, user_id bigint NOT NULL, total_amount decimal(12,2) NOT NULL COMMENT 商品总金额, pay_amount decimal(12,2) NOT NULL COMMENT 实付金额, status tinyint NOT NULL DEFAULT 0 COMMENT 0待支付 1待发货 2待收货 3已完成 4已关闭, receiver_name varchar(64) NOT NULL, receiver_phone varchar(20) NOT NULL, receiver_address varchar(255) NOT NULL, pay_time datetime DEFAULT NULL, ship_time datetime DEFAULT NULL, finish_time datetime DEFAULT NULL, remark varchar(255) DEFAULT , create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_order_no (order_no), KEY idx_user (user_id), KEY idx_status (status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT订单主表; -- 订单明细表 CREATE TABLE t_order_item ( id bigint NOT NULL AUTO_INCREMENT, order_id bigint NOT NULL, goods_id bigint NOT NULL, sku_id bigint NOT NULL, goods_name varchar(128) NOT NULL, sku_name varchar(128) NOT NULL, sku_image varchar(500) DEFAULT , price decimal(12,2) NOT NULL COMMENT 下单时单价快照, count int NOT NULL, create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_order (order_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT订单明细表;这里把订单金额做了快照因为在珠宝类目中商品价格可能变动如果不存快照日后售后、对账、结算都会很困难。3. SpringBoot 后端接口开发实战3.1 创建工程和引入依赖后端工程适合按模块分层组织例如jewelry-mall-server ├── src/main/java/com/jewelry/mall │ ├── common // 统一返回、全局异常 │ ├── config // 跨域、拦截器 │ ├── controller // 接口层 │ ├── entity // 数据库实体 │ ├── mapper // MyBatis-Plus Mapper │ ├── service // 业务逻辑 │ └── util // Token 等工具 ├── src/main/resources │ ├── application.yml │ └── mapperpom.xml 中比较关键的依赖如下parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version3.2.5/version relativePath/ /parent dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-validation/artifactId /dependency dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-spring-boot3-starter/artifactId version3.5.7/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-j/artifactId scoperuntime/scope /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency /dependencies版本是一个值得注意的点。如果你本机 Maven 仓库无法拉取上面版本请优先替换成当前可用的最新稳定版本Spring Boot 3.x 需要搭配 JDK 17 及以上。application.yml 示例server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/jewelry_mall?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver mybatis-plus: configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0数据库密码不要直接写入生产配置。这里只作为本地开发示例。3.2 统一接口返回结果商城接口如果每次返回结构不同前端就会写大量兼容代码。建议后端统一使用 Result 结构// 文件路径src/main/java/com/jewelry/mall/common/Result.java package com.jewelry.mall.common; import lombok.Data; Data public class ResultT { private Integer code; private String message; private T data; public static T ResultT ok(T data) { ResultT result new Result(); result.setCode(200); result.setMessage(success); result.setData(data); return result; } public static T ResultT fail(String message) { ResultT result new Result(); result.setCode(500); result.setMessage(message); return result; } }这样前端 axios 拦截器就可以只针对code 200做正常数据处理遇到其它 code 时统一弹错误提示。3.3 商品分页查询接口使用 MyBatis-Plus 时商品分页可以这样编写// 文件路径src/main/java/com/jewelry/mall/entity/Goods.java package com.jewelry.mall.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import java.time.LocalDateTime; Data TableName(t_goods) public class Goods { TableId(type IdType.AUTO) private Long id; private String name; private String subtitle; private Long categoryId; private String mainImage; private String detailImages; private String material; private String certNo; private Integer status; private Integer sort; private Integer sales; private LocalDateTime createTime; private LocalDateTime updateTime; }分页 Controller// 文件路径src/main/java/com/jewelry/mall/controller/ProductController.java package com.jewelry.mall.controller; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.jewelry.mall.common.Result; import com.jewelry.mall.entity.Goods; import com.jewelry.mall.mapper.GoodsMapper; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; RestController RequestMapping(/api/goods) public class ProductController { private final GoodsMapper goodsMapper; public ProductController(GoodsMapper goodsMapper) { this.goodsMapper goodsMapper; } GetMapping(/page) public ResultPageGoods page(RequestParam(defaultValue 1) long page, RequestParam(defaultValue 10) long size, RequestParam(required false) Long categoryId, RequestParam(required false) String keyword) { LambdaQueryWrapperGoods wrapper new LambdaQueryWrapper(); // 小程序端商品列表只展示上架商品 wrapper.eq(Goods::getStatus, 1); if (categoryId ! null) { wrapper.eq(Goods::getCategoryId, categoryId); } if (StringUtils.hasText(keyword)) { wrapper.like(Goods::getName, keyword); } wrapper.orderByDesc(Goods::getSort); PageGoods pageResult goodsMapper.selectPage(new Page(page, size), wrapper); return Result.ok(pageResult); } }这段代码里使用了 LambdaQueryWrapper好处是字段名有编译期提示不容易因为拼写错误导致 SQL 异常。如果使用原生 MyBatis同样建议按 XML 文件维护 SQL避免业务 SQL 堆在 Controller 里。3.4 登录鉴权处理小程序端一般使用微信登录。安全起见小程序的code只能交给后端去微信接口换取openid。基本流程是小程序调用wx.login()获取临时 code。小程序把 code 传给后端登录接口。后端向微信接口https://api.weixin.qq.com/sns/jscode2session换取 openid。后端查询用户是否存在不存在就创建用户。后端生成 token 返回给小程序。这里的appid和secret必须放在后端配置中不能打包进小程序代码。为了不让示例过度依赖第三方 JWT 库我展示一种简单的“自签名 token”思路生产环境建议替换为成熟方案或 Sa-Token、Spring Security// 文件路径src/main/java/com/jewelry/mall/util/TokenUtils.java package com.jewelry.mall.util; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.UUID; public class TokenUtils { private static final String SECRET jewelry-mall-2024-secret; public static String createToken(Long userId) { String header Base64.getUrlEncoder().withoutPadding() .encodeToString({\alg\:\HS256\}.getBytes(StandardCharsets.UTF_8)); String payload Base64.getUrlEncoder().withoutPadding() .encodeToString(({\userId\: userId ,\nonce\:\ UUID.randomUUID() \}) .getBytes(StandardCharsets.UTF_8)); String content header . payload; String signature hmacSha256(content, SECRET); return content . signature; } public static String hmacSha256(String data, String secret) { try { Mac mac Mac.getInstance(HmacSHA256); SecretKeySpec keySpec new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), HmacSHA256); mac.init(keySpec); byte[] bytes mac.doFinal(data.getBytes(StandardCharsets.UTF_8)); return Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); } catch (Exception e) { throw new RuntimeException(token sign error, e); } } }登录接口的核心伪代码可以这样理解public String login(String code) { // 1. 使用 code 调用微信接口获取 openid String openid wechatService.code2Session(code); // 2. 若用户不存在则创建 User user userMapper.selectOne(new LambdaQueryWrapperUser() .eq(User::getOpenid, openid)); if (user null) { user new User(); user.setOpenid(openid); user.setNickname(珠宝用户); userMapper.insert(user); } // 3. 生成并返回 token return TokenUtils.createToken(user.getId()); }拦截器在校验 token 后可以把 userId 写入 ThreadLocal供后续 Controller 获取。这一点在订单、购物车等需要用户信息的接口中非常关键。3.5 下单接口与库存扣减珠宝商城的核心交易逻辑在下单。很多初学者直接在前端计算订单金额再传到后端这是非常危险的做法。正确思路是前端只传skuId count和收货地址 id。后端从数据库重新查询每项 SKU 的真实价格和库存。后端使用事务保证多个 SKU 扣库存要么全部成功要么全部回滚。使用乐观锁 SQL 防止超卖。Service 核心逻辑// 文件路径src/main/java/com/jewelry/mall/service/OrderService.java package com.jewelry.mall.service; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.jewelry.mall.entity.GoodsSku; import com.jewelry.mall.entity.Order; import com.jewelry.mall.entity.OrderItem; import com.jewelry.mall.mapper.GoodsSkuMapper; import com.jewelry.mall.mapper.OrderItemMapper; import com.jewelry.mall.mapper.OrderMapper; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.util.List; Service public class OrderService { private final GoodsSkuMapper goodsSkuMapper; private final OrderMapper orderMapper; private final OrderItemMapper orderItemMapper; public OrderService(GoodsSkuMapper goodsSkuMapper, OrderMapper orderMapper, OrderItemMapper orderItemMapper) { this.goodsSkuMapper goodsSkuMapper; this.orderMapper orderMapper; this.orderItemMapper orderItemMapper; } Transactional(rollbackFor Exception.class) public Order createOrder(Long userId, ListOrderItemParam items) { BigDecimal totalAmount BigDecimal.ZERO; for (OrderItemParam param : items) { // 1. 扣减库存stock count 条件可以防止超卖 int rows goodsSkuMapper.deductStock(param.getSkuId(), param.getCount()); if (rows 0) { throw new RuntimeException(库存不足请重新选择商品); } // 2. 查询 SKU 价格 GoodsSku sku goodsSkuMapper.selectById(param.getSkuId()); totalAmount totalAmount.add(sku.getPrice().multiply(BigDecimal.valueOf(param.getCount()))); } // 3. 生成订单主表和明细表这里省略接收地址等参数 Order order new Order(); order.setPayAmount(totalAmount); order.setTotalAmount(totalAmount); orderMapper.insert(order); return order; } }对应的 Mapper 库存扣减方法Update(update t_goods_sku set stock stock - #{count} where id #{skuId} and stock #{count}) int deductStock(Param(skuId) Long skuId, Param(count) Integer count);这里的关键点在于更新 SQL 必须带stock #{count}条件。如果更新影响行数为 0说明库存不足或 SKU 失效业务直接抛异常回滚即可。4. Vue3 管理后台开发实战4.1 初始化 Vue3 项目管理后台适合使用 Vite 构建。如果是从零开始可以执行npm create vitelatest jewelry-admin -- --template vue cd jewelry-admin npm install npm install axios pinia vue-router element-plus element-plus/icons-vue npm run dev执行后得到一个 Vue3 工程。建议目录结构为src ├── api // 接口模块 ├── assets ├── components // 公共组件 ├── router // 路由 ├── stores // Pinia 状态 ├── utils // 工具 ├── views // 页面 │ ├── goods │ ├── order │ └── dashboard ├── App.vue └── main.js4.2 Axios 请求封装不管后台页面有多少个axios 封装一定要做统一处理。否则每个页面都写一遍错误提示和登录跳转会非常痛苦。// 文件路径src/utils/request.js import axios from axios import { ElMessage } from element-plus import router from ../router import { useAdminStore } from ../stores/admin const request axios.create({ baseURL: /api, timeout: 10000 }) request.interceptors.request.use(config { const adminStore useAdminStore() if (adminStore.token) { config.headers[Authorization] adminStore.token } return config }) request.interceptors.response.use( response { const res response.data if (res.code 200) { return res.data } ElMessage.error(res.message || 请求失败) return Promise.reject(new Error(res.message)) }, error { if (error.response error.response.status 401) { ElMessage.error(登录已过期请重新登录) router.push(/login) } else { ElMessage.error(网络异常请稍后重试) } return Promise.reject(error) } ) export default request4.3 登录状态管理Pinia 是 Vue3 推荐的状态管理方案。用组合式 API 写起来非常自然// 文件路径src/stores/admin.js import { defineStore } from pinia export const useAdminStore defineStore(admin, { state: () ({ token: localStorage.getItem(admin_token) || , adminName: localStorage.getItem(admin_name) || }), getters: { isLogin: state !!state.token }, actions: { setLoginInfo(token, name) { this.token token this.adminName name localStorage.setItem(admin_token, token) localStorage.setItem(admin_name, name) }, logout() { this.token this.adminName localStorage.removeItem(admin_token) localStorage.removeItem(admin_name) } } })路由守卫里调用isLogin判断是否允许进入页面。4.4 商品管理页面示例商品管理后台的核心动作是新增商品、编辑 SKU、上架/下架、查看库存。一个相对精简的商品表格页面如下template div classgoods-page el-card div classtoolbar el-input v-modelquery.name placeholder请输入商品名称 clearable stylewidth: 220px / el-button typeprimary clickloadData查询/el-button el-button typesuccess clickhandleCreate新增商品/el-button /div el-table :datalist v-loadingloading border el-table-column propid labelID width80 / el-table-column propname label商品名称 min-width160 / el-table-column label主图 width100 template #default{ row } el-image stylewidth: 48px; height: 48px :srcrow.mainImage fitcover / /template /el-table-column el-table-column label状态 width120 template #default{ row } el-tag :typerow.status 1 ? success : info {{ statusText(row.status) }} /el-tag /template /el-table-column el-table-column label操作 width200 template #default{ row } el-button link typeprimary clickhandleEdit(row)编辑/el-button el-button link :typerow.status 1 ? warning : success clicktoggleStatus(row) {{ row.status 1 ? 下架 : 上架 }} /el-button /template /el-table-column /el-table el-pagination classpagination background layouttotal, prev, pager, next :totaltotal v-model:current-pagequery.page v-model:page-sizequery.size current-changeloadData / /el-card /div /template script setup import { computed, reactive, ref } from vue import { ElMessage } from element-plus import { getGoodsPage, updateGoodsStatus } from ../../api/goods const loading ref(false) const list ref([]) const total ref(0) const query reactive({ name: , page: 1, size: 10 }) const statusText computed(() (status) { return status 1 ? 上架中 : 已下架 }) async function loadData() { loading.value true try { const data await getGoodsPage(query) list.value data.records total.value Number(data.total) } finally { loading.value false } } async function toggleStatus(row) { const nextStatus row.status 1 ? 0 : 1 await updateGoodsStatus(row.id, nextStatus) ElMessage.success(操作成功) loadData() } function handleCreate() { // 跳转新增商品页或打开商品编辑弹窗 } function handleEdit(row) { // 跳转编辑页并
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

第一款Mac app就获97%媒体评分?关键在于发布前的工程细节 2026/9/4 18:39:57

第一款Mac app就获97%媒体评分?关键在于发布前的工程细节

那天刷新 Show HN 的时候,我注意到一条标题:My first app got 97% on MacSources。发帖人没有写长篇功能清单,没有讲解技术栈,也没有放几十张截图,只是把一个结果放在那里。评论区里有人恭喜,有人询问这款具…

阅读更多 →
光通信原理、器件与系统设计完全指南:从光波到数据中心 2026/9/4 18:39:57

光通信原理、器件与系统设计完全指南:从光波到数据中心

一、前言:光通信为何统治现代通信? 你正在看的网页、刷的视频、打的电话,最终都可能是光在玻璃纤维里跑。光通信的诞生是通信史的革命——容量大、距离远、抗干扰、保密性强,让"信息高速公路"成为可能。 本文系统讲解光…

阅读更多 →
Spark Streaming 反压机制原理剖析:从控制论到生产调优实战 2026/9/4 18:39:57

Spark Streaming 反压机制原理剖析:从控制论到生产调优实战

一、前言:反压是什么?为什么重要? 在流式计算中,上游生产速度 > 下游消费速度是常见场景——比如双 11 大促期间,Kafka 涌入的订单数据量瞬间暴增,Spark Streaming 来不及处理,任务就开始&qu…

阅读更多 →
服务评价文本情感分类实战 从 Kaggle 竞赛到可落地的评论分析方案 2026/9/4 18:39:57

服务评价文本情感分类实战 从 Kaggle 竞赛到可落地的评论分析方案

这道 Kaggle 竞赛围绕服务评价评论的情感识别展开,核心任务是把非结构化文本转成可计算的类别结果。题面信息不复杂,但很适合用来完整演练文本分类项目中的关键环节,包括任务界定、数据理解、基线搭建、特征表示、验证设计与误差分析。 更有…

阅读更多 →
莫斯科公寓价格预测实战 从 Kaggle 房价回归到可落地估值流程 2026/9/4 18:39:57

莫斯科公寓价格预测实战 从 Kaggle 房价回归到可落地估值流程

这道 Kaggle 题目的核心并不在比赛名,而在一个非常典型的业务问题:依据房源的结构化特征预测莫斯科公寓价格。任务形式是标准回归,但真正有价值的部分在于,完整覆盖了房价建模中最常见的难点,包括目标分布偏态、异常样…

阅读更多 →
Delphi 12.3集成Aspose.Words v24.10.0:实现企业级Word文档自动化处理 2026/9/4 18:36:56

Delphi 12.3集成Aspose.Words v24.10.0:实现企业级Word文档自动化处理

简介:本资源是面向Delphi 12.3开发者的技术集成包,专为在原生Delphi环境中调用Aspose Words for .NET文档处理能力而设计,解决跨平台Word文档创建、编辑、格式转换(如DOCX→PDF/HTML)及渲染等核心需求,适用…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞