diff --git a/admin/src/api/product.ts b/admin/src/api/product.ts
index 53256b1d..0164691e 100644
--- a/admin/src/api/product.ts
+++ b/admin/src/api/product.ts
@@ -39,3 +39,15 @@ export function importSpecData(productId: number, file: File) {
headers: { 'Content-Type': 'multipart/form-data' },
})
}
+
+export function getSpecDataList(productId: number) {
+ return http.get(`/admin/products/${productId}/spec-data`)
+}
+
+export function createSpecData(productId: number, data: any) {
+ return http.post(`/admin/products/${productId}/spec-data`, data)
+}
+
+export function deleteSpecData(productId: number, specId: number) {
+ return http.delete(`/admin/products/${productId}/spec-data/${specId}`)
+}
diff --git a/admin/src/layout/AdminLayout.vue b/admin/src/layout/AdminLayout.vue
index bb8f4940..823f510e 100644
--- a/admin/src/layout/AdminLayout.vue
+++ b/admin/src/layout/AdminLayout.vue
@@ -9,6 +9,9 @@
商品管理
+
+ 分类管理
+
订单管理
diff --git a/admin/src/router/index.ts b/admin/src/router/index.ts
index 9b961aff..929850ba 100644
--- a/admin/src/router/index.ts
+++ b/admin/src/router/index.ts
@@ -44,6 +44,11 @@ const router = createRouter({
name: 'MoldList',
component: () => import('../views/mold/MoldList.vue'),
},
+ {
+ path: 'categories',
+ name: 'CategoryList',
+ component: () => import('../views/category/CategoryList.vue'),
+ },
],
},
],
diff --git a/admin/src/views/category/CategoryList.vue b/admin/src/views/category/CategoryList.vue
new file mode 100644
index 00000000..b6de8ff6
--- /dev/null
+++ b/admin/src/views/category/CategoryList.vue
@@ -0,0 +1,117 @@
+
+
+
分类管理
+
+ 新增分类
+
+
+
+
+
+
+ 无
+
+
+
+
+
+
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 上传图标
+
+
+
+
+ 取消
+ 确定
+
+
+
+
+
+
diff --git a/admin/src/views/product/ProductForm.vue b/admin/src/views/product/ProductForm.vue
index 58723866..d15054c4 100644
--- a/admin/src/views/product/ProductForm.vue
+++ b/admin/src/views/product/ProductForm.vue
@@ -33,6 +33,24 @@
+
+
+
+ +
+
+ 用于商品列表页展示的缩略图
+
+
详细参数配置
-
-
+
+ {{ tag }}
+
+
-
-
+
+ {{ tag }}
+
+
-
-
+
+ {{ tag }}
+
+
-
+
规格数据管理
-
+
导出 CSV
导入 CSV
+ 新增规格
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 删除
+
+
+
+
+
+ 暂无规格数据,请通过 CSV 导入或手动新增
+
+
+
+
+
+
+
+
+
+
+
+ 金料信息
+
+
+
+
+
+
+
+
+
+
+ 主石信息
+
+
+
+
+
+
+ 副石信息
+
+
+
+
+
+
+ 工费信息
+
+
+
+
+
+
+
+
+
+
+
+ 取消
+ 确定
+
+
+
保存
取消
@@ -107,8 +222,8 @@
+
+
diff --git a/miniprogram/api/product.ts b/miniprogram/api/product.ts
index 6d7556fd..8b6e915e 100644
--- a/miniprogram/api/product.ts
+++ b/miniprogram/api/product.ts
@@ -14,7 +14,7 @@ export const getProductSpecs = (id: number) =>
get(`/api/products/${id}/specs`)
/** 根据参数组合获取规格数据列表 */
-export const getSpecDataList = (id: number, params: { fineness: string; mainStone: string; ringSize: string }) =>
+export const getSpecDataList = (id: number, params: { fineness?: string; mainStone?: string; ringSize?: string }) =>
post(`/api/products/${id}/spec-data`, params as unknown as Record)
/** 获取商品分类列表 */
diff --git a/miniprogram/components/BannerSwiper.vue b/miniprogram/components/BannerSwiper.vue
index e2e01637..bab66a13 100644
--- a/miniprogram/components/BannerSwiper.vue
+++ b/miniprogram/components/BannerSwiper.vue
@@ -1,34 +1,31 @@
-
-
+
-
-
+
diff --git a/miniprogram/components/ProductCard.vue b/miniprogram/components/ProductCard.vue
index d68a0816..b7be9279 100644
--- a/miniprogram/components/ProductCard.vue
+++ b/miniprogram/components/ProductCard.vue
@@ -1,76 +1,85 @@
-
-
-
- {{ product.name }}
- 款号:{{ product.styleNo }}
-
- ¥{{ product.basePrice }}
- 库存 {{ product.stock }}
-
-
-
+
+
+
+ {{ product.name }}({{ product.styleNo }})
+
+
+ ¥{{ product.basePrice }}
+
+ 库存{{ product.stock }}
+
+
+
+ .product-card {
+ display: flex;
+ flex-direction: column;
+ background: #fff;
+ border-radius: 16rpx;
+ overflow: hidden;
+ width: 100%;
+ }
+
+ .product-card__image {
+ width: 100%;
+ height: 340rpx;
+ }
+
+ .product-card__info {
+ padding: 16rpx 20rpx 20rpx;
+ }
+
+ .product-card__name {
+ font-size: 26rpx;
+ color: #333;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ display: block;
+ line-height: 1.5;
+ }
+
+ .product-card__bottom {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-top: 12rpx;
+ }
+
+ .product-card__price-tag {
+ background: linear-gradient(135deg, #f5a0b8, #FF6D9B);
+ border-radius: 8rpx;
+ padding: 4rpx 16rpx;
+ }
+
+ .product-card__price {
+ font-size: 28rpx;
+ color: #fff;
+ font-weight: bold;
+ }
+
+ .product-card__stock {
+ font-size: 22rpx;
+ color: #999;
+ }
+
\ No newline at end of file
diff --git a/miniprogram/components/ShippingNotice.vue b/miniprogram/components/ShippingNotice.vue
index e77e56fb..87b399ce 100644
--- a/miniprogram/components/ShippingNotice.vue
+++ b/miniprogram/components/ShippingNotice.vue
@@ -1,9 +1,15 @@
- 发货公告
- 交易方式:线下支付,微信沟通确认
- 客服微信:请点击「联系客服」获取
- 公司地址:请联系客服获取详细地址
+
+
+ 叶生珠宝-空托之城空托都是当天金工石结算
+ 客服微信:15920028399
+ 交易方式:加微信门店交易,支付宝,微信,银行卡转账
+ 公司地址:深圳市罗湖区水贝二路贝丽花园21栋108叶生珠宝
+
@@ -12,20 +18,34 @@
diff --git a/miniprogram/components/SpecPanel.vue b/miniprogram/components/SpecPanel.vue
index a5a91123..95df2f2b 100644
--- a/miniprogram/components/SpecPanel.vue
+++ b/miniprogram/components/SpecPanel.vue
@@ -1,281 +1,317 @@
-
-
+
+
+
+
+ 加载中...
-
- 加载中...
-
-
-
-
- 成色
-
-
- {{ item }}
+
+
+
+ 成 色
+
+ {{ item }}
-
-
-
- 主石
-
-
- {{ item }}
+
+
+ 主 石
+
+ {{ item }}
-
-
-
- 手寸
-
-
- {{ item }}
+
+
+ 手 寸
+
+ {{ item }}
-
-
-
-
-
- 查询规格数据
-
-
+
查询中...
-
-
- 型号
- {{ spec.modelName }}
+
+
+
-
- 金料总重
- {{ spec.goldTotalWeight }}g
+
+
+
+
+ 型号名称
+ {{ spec.modelName }}
+
+
+ 金料总重
+ {{ spec.goldTotalWeight }}g
+
+
+ 金料净重
+ {{ spec.goldNetWeight }}g
+
+
+ 金耗
+ {{ spec.goldLoss }}g
+
+
+ 金值
+ ¥{{ spec.goldValue }}
+
+
+ 主石数量
+ {{ spec.mainStoneCount }}粒
+
+
+ 主石石重
+ {{ spec.mainStoneWeight }}ct
+
+
+ 主石单价
+ ¥{{ spec.mainStoneUnitPrice }}
+
+
+ 主石金额
+ ¥{{ spec.mainStoneAmount }}
+
+
+ 配件金额
+ ¥{{ spec.accessoryAmount }}
+
+
+ 总工费
+ ¥{{ spec.totalLaborCost }}
+
+
+
+
+ 成色
+ {{ spec.fineness }}
+
+
+ 损耗
+ {{ spec.loss }}%
+
+
+ 主石
+ {{ spec.mainStone }}
+
+
+ 手寸
+ {{ spec.ringSize }}
+
+
+ 金价
+ ¥{{ spec.goldPrice }}
+
+
+ 副石数量
+ {{ spec.sideStoneCount }}粒
+
+
+ 副石石重
+ {{ spec.sideStoneWeight }}ct
+
+
+ 副石单价
+ ¥{{ spec.sideStoneUnitPrice }}
+
+
+ 副石金额
+ ¥{{ spec.sideStoneAmount }}
+
+
+ 加工工费
+ ¥{{ spec.processingFee }}
+
+
+ 镶石工费
+ ¥{{ spec.settingFee }}
+
+
-
- 金值
- ¥{{ spec.goldValue }}
-
-
- 主石金额
- ¥{{ spec.mainStoneAmount }}
-
-
- 副石金额
- ¥{{ spec.sideStoneAmount }}
-
-
- 总工费
- ¥{{ spec.totalLaborCost }}
-
-
- 总价
- ¥{{ spec.totalPrice }}
+
+
-
+
+
+
+
+
+ 加入购物车({{ selectedSpecs.size }})
+
+
diff --git a/miniprogram/pages.json b/miniprogram/pages.json
index 3607315c..d59600af 100644
--- a/miniprogram/pages.json
+++ b/miniprogram/pages.json
@@ -3,13 +3,13 @@
{
"path": "pages/index/index",
"style": {
- "navigationBarTitleText": "珠宝商城"
+ "navigationStyle": "custom"
}
},
{
"path": "pages/product/detail",
"style": {
- "navigationBarTitleText": "商品详情"
+ "navigationStyle": "custom"
}
},
{
diff --git a/miniprogram/pages/index/index.vue b/miniprogram/pages/index/index.vue
index 737e8bb0..a76cb601 100644
--- a/miniprogram/pages/index/index.vue
+++ b/miniprogram/pages/index/index.vue
@@ -1,131 +1,309 @@
-
-
-
-
- {{ cat.name }}
-
-
+
+
+
+
+ 凯缘钻之城
+
+
-
-
-
-
-
-
+
+
+
+
+ 请输入产品名称、款号、条码号或款式
+
+ 搜索
+
-
-
- 暂无商品
-
+
+
+
+
+
+
+ 💎
+
+ {{ cat.name }}
+
+
+
-
-
- 加载中...
-
-
+
+
+
+ 💎
+ 钻戒计算器
+
+
+ 👩💼
+ 客服找款
+
+
+
+
+
+
+
+
+
+
+
+
+ 暂无商品
+
+
+
+
+ 加载中...
+
+
+
+
+
+ .home-page {
+ min-height: 100vh;
+ background: #f5f5f5;
+ }
+
+ /* 自定义导航栏 */
+ .custom-navbar {
+ background: linear-gradient(to right, #FFCFDE, #FFA6C4);
+ }
+
+ .custom-navbar__content {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .custom-navbar__title {
+ font-size: 34rpx;
+ font-weight: bold;
+ color: #333;
+ }
+
+ /* 搜索栏 */
+ .search-bar {
+ display: flex;
+ align-items: center;
+ padding: 16rpx 24rpx;
+ }
+
+ .search-bar__input {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ background: #fff;
+ border-radius: 40rpx;
+ padding: 16rpx 24rpx;
+ height: 72rpx;
+ box-sizing: border-box;
+ }
+
+ .search-bar__icon {
+ width: 32rpx;
+ height: 32rpx;
+ margin-right: 12rpx;
+ }
+
+ .search-bar__placeholder {
+ font-size: 24rpx;
+ color: #999;
+ }
+
+ .search-bar__btn {
+ margin-left: 16rpx;
+ font-size: 28rpx;
+ color: #333;
+ font-weight: 500;
+ }
+
+ /* 分类图标 */
+ .category-section {
+ white-space: nowrap;
+ padding: 32rpx 0 24rpx;
+ background: #FFFFFF;
+ }
+
+ .category-section__inner {
+ display: inline-flex;
+ padding: 0 24rpx;
+ gap: 32rpx;
+ }
+
+ .category-icon {
+ display: inline-flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 12rpx;
+ flex-shrink: 0;
+ }
+
+ .category-icon__circle {
+ width: 120rpx;
+ height: 120rpx;
+ border-radius: 30rpx;
+ background: linear-gradient(135deg, #fce4ec, #f8bbd0);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .category-icon--active .category-icon__circle {
+ background: linear-gradient(135deg, #f48fb1, #e91e63);
+ box-shadow: 0 4rpx 16rpx rgba(233, 30, 99, 0.3);
+ }
+
+ .category-icon__emoji {
+ font-size: 48rpx;
+ }
+
+ .category-icon__img {
+ width: 90rpx;
+ height: 90rpx;
+ }
+
+ .category-icon__label {
+ font-size: 24rpx;
+ color: #333;
+ }
+
+ .category-icon--active .category-icon__label {
+ color: #e91e63;
+ font-weight: bold;
+ }
+
+ /* 快捷入口 */
+ .quick-actions {
+ display: flex;
+ gap: 20rpx;
+ padding: 0 24rpx 24rpx;
+ background-color: #FFFFFF;
+ }
+
+ .quick-action {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 16rpx;
+ padding: 28rpx 0;
+ border-radius: 16rpx;
+ background: #fff;
+ }
+
+ .quick-action--calc {
+ background: linear-gradient(135deg, #FFA4C3, #FFD2E0);
+ }
+
+ .quick-action--service {
+ background: linear-gradient(135deg, #e8f5e9, #fff);
+ }
+
+ .quick-action__icon {
+ font-size: 44rpx;
+ }
+
+ .quick-action__text {
+ font-size: 30rpx;
+ color: #333;
+ font-weight: 600;
+ }
+
+ /* 商品列表 */
+ .product-grid {
+ display: flex;
+ flex-wrap: wrap;
+ padding: 0 24rpx;
+ gap: 16rpx;
+ }
+
+ .product-grid__item {
+ width: calc(50% - 8rpx);
+ }
+
+ .empty-tip,
+ .loading-tip {
+ text-align: center;
+ padding: 60rpx 0;
+ color: #999;
+ font-size: 28rpx;
+ }
+
\ No newline at end of file
diff --git a/miniprogram/pages/product/detail.vue b/miniprogram/pages/product/detail.vue
index 2a6868db..94fbdc0e 100644
--- a/miniprogram/pages/product/detail.vue
+++ b/miniprogram/pages/product/detail.vue
@@ -1,26 +1,42 @@
-
-
+
+
+
+
+ 商品详情
+
+
+
-
+
+
+
+
+
+
+
+
+
- ¥{{ product.basePrice }}
- {{ product.name }}
+
+ {{ product.name }}
+
+ ¥
+ {{ product.basePrice }}
+ 元
+
+
- 款号
+ 款 号
{{ product.styleNo }}
-
-
库存
{{ product.stock }}
- 损耗
- {{ product.loss }}
-
-
+ 损 耗
+ {{ product.loss }}%
工费
¥{{ product.laborCost }}
@@ -30,25 +46,40 @@
-
-
- 查看详细参数
- ›
+
+
+ 商品详情
+
+
+
-
-
-
- 客服
- 加入购物车
+
+
+
+ 客服
+
+
+
+ 购物车
+
+
+
+ 空托—查看详细参数
+
+
+
+
@@ -56,9 +87,9 @@
diff --git a/miniprogram/static/ic_back.png b/miniprogram/static/ic_back.png
new file mode 100644
index 00000000..0166203b
Binary files /dev/null and b/miniprogram/static/ic_back.png differ
diff --git a/miniprogram/static/ic_notice.png b/miniprogram/static/ic_notice.png
new file mode 100644
index 00000000..4c940a83
Binary files /dev/null and b/miniprogram/static/ic_notice.png differ
diff --git a/miniprogram/static/ic_search.png b/miniprogram/static/ic_search.png
new file mode 100644
index 00000000..b0c04b82
Binary files /dev/null and b/miniprogram/static/ic_search.png differ
diff --git a/miniprogram/store/cart.ts b/miniprogram/store/cart.ts
index c5ea70e8..3de2a9a4 100644
--- a/miniprogram/store/cart.ts
+++ b/miniprogram/store/cart.ts
@@ -1,22 +1,19 @@
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import type { CartItem } from '../types'
+import { getCartList, addToCart as apiAddToCart, deleteCartItem as apiDeleteCartItem, updateCartItem as apiUpdateCartItem } from '../api/cart'
export const useCartStore = defineStore('cart', () => {
const items = ref([])
- /** 已勾选的商品 */
const checkedItems = computed(() => items.value.filter((item) => item.checked))
- /** 已勾选商品总金额 */
const totalAmount = computed(() =>
checkedItems.value.reduce((sum, item) => sum + item.specData.totalPrice * item.quantity, 0),
)
- /** 从后端拉取购物车列表并同步到本地 */
async function fetchCart() {
try {
- const { getCartList } = await import('../api/cart')
const list = await getCartList()
items.value = list.map((item) => ({ ...item, checked: true }))
} catch {
@@ -24,38 +21,28 @@ export const useCartStore = defineStore('cart', () => {
}
}
- /** 添加商品到购物车(本地优先,后台同步) */
function addToCart(item: CartItem) {
items.value.push(item)
- // 异步同步到后端
- import('../api/cart').then(({ addToCart: apiAdd }) => {
- apiAdd({
- productId: item.productId,
- specDataId: item.specDataId,
- quantity: item.quantity,
- }).catch(() => { /* 静默处理 */ })
+ apiAddToCart({
+ productId: item.productId,
+ specDataId: item.specDataId,
+ quantity: item.quantity,
}).catch(() => { /* 静默处理 */ })
}
- /** 移除购物车项 */
function removeFromCart(id: number) {
const index = items.value.findIndex((item) => item.id === id)
if (index !== -1) {
items.value.splice(index, 1)
- import('../api/cart').then(({ deleteCartItem }) => {
- deleteCartItem(id).catch(() => { /* 静默处理 */ })
- }).catch(() => { /* 静默处理 */ })
+ apiDeleteCartItem(id).catch(() => { /* 静默处理 */ })
}
}
- /** 更新数量 */
function updateQuantity(id: number, quantity: number) {
const item = items.value.find((item) => item.id === id)
if (item) {
item.quantity = quantity
- import('../api/cart').then(({ updateCartItem }) => {
- updateCartItem(id, { quantity }).catch(() => { /* 静默处理 */ })
- }).catch(() => { /* 静默处理 */ })
+ apiUpdateCartItem(id, { quantity }).catch(() => { /* 静默处理 */ })
}
}
diff --git a/miniprogram/types/product.ts b/miniprogram/types/product.ts
index a160fdd5..76ee658e 100644
--- a/miniprogram/types/product.ts
+++ b/miniprogram/types/product.ts
@@ -11,6 +11,7 @@ export interface Product {
categoryId: number
bannerImages: string[]
bannerVideo?: string
+ thumb?: string
status: 'on' | 'off'
createdAt: string
updatedAt: string
@@ -20,6 +21,7 @@ export interface Product {
export interface Category {
id: number
name: string
+ icon?: string
parentId?: number
sort: number
}
diff --git a/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/api/cart.js.map b/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/api/cart.js.map
index a61e4a87..72c81328 100644
--- a/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/api/cart.js.map
+++ b/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/api/cart.js.map
@@ -1 +1 @@
-{"version":3,"file":"cart.js","sources":["api/cart.ts"],"sourcesContent":["import { get, post, put, del } from '../utils/request'\r\nimport type { CartItem } from '../types'\r\n\r\n/** 获取购物车列表 */\r\nexport const getCartList = () =>\r\n get('/api/cart')\r\n\r\n/** 添加商品到购物车 */\r\nexport const addToCart = (data: { productId: number; specDataId: number; quantity: number }) =>\r\n post('/api/cart', data as unknown as Record)\r\n\r\n/** 更新购物车项 */\r\nexport const updateCartItem = (id: number, data: { quantity: number }) =>\r\n put(`/api/cart/${id}`, data as unknown as Record)\r\n\r\n/** 删除购物车项 */\r\nexport const deleteCartItem = (id: number) =>\r\n del(`/api/cart/${id}`)\r\n"],"names":["get","post","put","del"],"mappings":";;;AAIa,MAAA,cAAc,MACzBA,cAAA,IAAgB,WAAW;AAGtB,MAAM,YAAY,CAAC,SACxBC,mBAAe,aAAa,IAA0C;AAG3D,MAAA,iBAAiB,CAAC,IAAY,SACzCC,cAAAA,IAAc,aAAa,EAAE,IAAI,IAA0C;AAGtE,MAAM,iBAAiB,CAAC,OAC7BC,cAAAA,IAAI,aAAa,EAAE,EAAE;;;;;"}
\ No newline at end of file
+{"version":3,"file":"cart.js","sources":["api/cart.ts"],"sourcesContent":["import { get, post, put, del } from '../utils/request'\r\nimport type { CartItem } from '../types'\r\n\r\n/** 获取购物车列表 */\r\nexport const getCartList = () =>\r\n get('/api/cart')\r\n\r\n/** 添加商品到购物车 */\r\nexport const addToCart = (data: { productId: number; specDataId: number; quantity: number }) =>\r\n post('/api/cart', data as unknown as Record)\r\n\r\n/** 更新购物车项 */\r\nexport const updateCartItem = (id: number, data: { quantity: number }) =>\r\n put(`/api/cart/${id}`, data as unknown as Record)\r\n\r\n/** 删除购物车项 */\r\nexport const deleteCartItem = (id: number) =>\r\n del(`/api/cart/${id}`)\r\n"],"names":["get","post","put","del"],"mappings":";;AAIa,MAAA,cAAc,MACzBA,cAAA,IAAgB,WAAW;AAGtB,MAAM,YAAY,CAAC,SACxBC,mBAAe,aAAa,IAA0C;AAG3D,MAAA,iBAAiB,CAAC,IAAY,SACzCC,cAAAA,IAAc,aAAa,EAAE,IAAI,IAA0C;AAGtE,MAAM,iBAAiB,CAAC,OAC7BC,cAAAA,IAAI,aAAa,EAAE,EAAE;;;;;"}
\ No newline at end of file
diff --git a/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/api/product.js.map b/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/api/product.js.map
index 6b7c1ecf..a1b96dd8 100644
--- a/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/api/product.js.map
+++ b/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/api/product.js.map
@@ -1 +1 @@
-{"version":3,"file":"product.js","sources":["api/product.ts"],"sourcesContent":["import { get, post } from '../utils/request'\r\nimport type { Product, Category, DetailParameterConfig, SpecData } from '../types'\r\n\r\n/** 获取商品列表 */\r\nexport const getProducts = (params?: { categoryId?: number; page?: number; pageSize?: number }) =>\r\n get<{ list: Product[]; total: number }>('/api/products', params as Record)\r\n\r\n/** 获取商品详情 */\r\nexport const getProductDetail = (id: number) =>\r\n get(`/api/products/${id}`)\r\n\r\n/** 获取商品详细参数选项 */\r\nexport const getProductSpecs = (id: number) =>\r\n get(`/api/products/${id}/specs`)\r\n\r\n/** 根据参数组合获取规格数据列表 */\r\nexport const getSpecDataList = (id: number, params: { fineness: string; mainStone: string; ringSize: string }) =>\r\n post(`/api/products/${id}/spec-data`, params as unknown as Record)\r\n\r\n/** 获取商品分类列表 */\r\nexport const getCategories = () =>\r\n get('/api/categories')\r\n"],"names":["get","post"],"mappings":";;AAIO,MAAM,cAAc,CAAC,WAC1BA,kBAAwC,iBAAiB,MAAiC;AAGrF,MAAM,mBAAmB,CAAC,OAC/BA,cAAAA,IAAa,iBAAiB,EAAE,EAAE;AAG7B,MAAM,kBAAkB,CAAC,OAC9BA,cAA2B,IAAA,iBAAiB,EAAE,QAAQ;AAG3C,MAAA,kBAAkB,CAAC,IAAY,WAC1CC,mBAAiB,iBAAiB,EAAE,cAAc,MAA4C;AAGnF,MAAA,gBAAgB,MAC3BD,cAAAA,IAAgB,iBAAiB;;;;;;"}
\ No newline at end of file
+{"version":3,"file":"product.js","sources":["api/product.ts"],"sourcesContent":["import { get, post } from '../utils/request'\r\nimport type { Product, Category, DetailParameterConfig, SpecData } from '../types'\r\n\r\n/** 获取商品列表 */\r\nexport const getProducts = (params?: { categoryId?: number; page?: number; pageSize?: number }) =>\r\n get<{ list: Product[]; total: number }>('/api/products', params as Record)\r\n\r\n/** 获取商品详情 */\r\nexport const getProductDetail = (id: number) =>\r\n get(`/api/products/${id}`)\r\n\r\n/** 获取商品详细参数选项 */\r\nexport const getProductSpecs = (id: number) =>\r\n get(`/api/products/${id}/specs`)\r\n\r\n/** 根据参数组合获取规格数据列表 */\r\nexport const getSpecDataList = (id: number, params: { fineness?: string; mainStone?: string; ringSize?: string }) =>\r\n post(`/api/products/${id}/spec-data`, params as unknown as Record)\r\n\r\n/** 获取商品分类列表 */\r\nexport const getCategories = () =>\r\n get('/api/categories')\r\n"],"names":["get","post"],"mappings":";;AAIO,MAAM,cAAc,CAAC,WAC1BA,kBAAwC,iBAAiB,MAAiC;AAGrF,MAAM,mBAAmB,CAAC,OAC/BA,cAAAA,IAAa,iBAAiB,EAAE,EAAE;AAG7B,MAAM,kBAAkB,CAAC,OAC9BA,cAA2B,IAAA,iBAAiB,EAAE,QAAQ;AAG3C,MAAA,kBAAkB,CAAC,IAAY,WAC1CC,mBAAiB,iBAAiB,EAAE,cAAc,MAA4C;AAGnF,MAAA,gBAAgB,MAC3BD,cAAAA,IAAgB,iBAAiB;;;;;;"}
\ No newline at end of file
diff --git a/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/common/assets.js.map b/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/common/assets.js.map
index 7971432a..f73ff1af 100644
--- a/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/common/assets.js.map
+++ b/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/common/assets.js.map
@@ -1 +1 @@
-{"version":3,"file":"assets.js","sources":["static/tab/me_s.png","static/ic_address.png","static/ic_customer.png","static/ic_about.png","static/ic_agreement1.png","static/ic_agreement2.png","static/logo.png"],"sourcesContent":["export default \"__VITE_ASSET__0724ec6f__\"","export default \"__VITE_ASSET__2fa96069__\"","export default \"__VITE_ASSET__834c867b__\"","export default \"__VITE_ASSET__53f234dc__\"","export default \"__VITE_ASSET__a736f8f4__\"","export default \"__VITE_ASSET__a25b5e1b__\"","export default \"__VITE_ASSET__46719607__\""],"names":[],"mappings":";AAAA,MAAe,eAAA;ACAf,MAAe,aAAA;ACAf,MAAe,aAAA;ACAf,MAAe,aAAA;ACAf,MAAe,aAAA;ACAf,MAAe,aAAA;ACAf,MAAe,aAAA;;;;;;;;"}
\ No newline at end of file
+{"version":3,"file":"assets.js","sources":["static/ic_search.png","static/ic_back.png","static/ic_customer.png","static/tab/car.png","static/tab/me_s.png","static/ic_address.png","static/ic_about.png","static/ic_agreement1.png","static/ic_agreement2.png","static/logo.png","static/ic_notice.png"],"sourcesContent":["export default \"__VITE_ASSET__cb299f1c__\"","export default \"__VITE_ASSET__a09e4f4f__\"","export default \"__VITE_ASSET__834c867b__\"","export default \"__VITE_ASSET__de453aec__\"","export default \"__VITE_ASSET__0724ec6f__\"","export default \"__VITE_ASSET__2fa96069__\"","export default \"__VITE_ASSET__53f234dc__\"","export default \"__VITE_ASSET__a736f8f4__\"","export default \"__VITE_ASSET__a25b5e1b__\"","export default \"__VITE_ASSET__46719607__\"","export default \"__VITE_ASSET__abe1da0c__\""],"names":[],"mappings":";AAAA,MAAe,eAAA;ACAf,MAAe,eAAA;ACAf,MAAe,eAAA;ACAf,MAAe,aAAA;ACAf,MAAe,eAAA;ACAf,MAAe,aAAA;ACAf,MAAe,aAAA;ACAf,MAAe,aAAA;ACAf,MAAe,aAAA;ACAf,MAAe,eAAA;ACAf,MAAe,aAAA;;;;;;;;;;;;"}
\ No newline at end of file
diff --git a/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/components/BannerSwiper.js.map b/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/components/BannerSwiper.js.map
index 0b46cbc0..f038e363 100644
--- a/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/components/BannerSwiper.js.map
+++ b/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/components/BannerSwiper.js.map
@@ -1 +1 @@
-{"version":3,"file":"BannerSwiper.js","sources":["../../../../Software/HBuilderX.4.76.2025082103/HBuilderX/plugins/uniapp-cli-vite/uniComponent:/RjovZ2l0Q29kZS91bmlhcHAvSmV3ZWxyeU1hbGwvbWluaXByb2dyYW0vY29tcG9uZW50cy9CYW5uZXJTd2lwZXIudnVl"],"sourcesContent":["import Component from 'F:/gitCode/uniapp/JewelryMall/miniprogram/components/BannerSwiper.vue'\nwx.createComponent(Component)"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AACA,GAAG,gBAAgB,SAAS;"}
\ No newline at end of file
+{"version":3,"file":"BannerSwiper.js","sources":["components/BannerSwiper.vue","../../../../Software/HBuilderX.4.76.2025082103/HBuilderX/plugins/uniapp-cli-vite/uniComponent:/RjovZ2l0Q29kZS91bmlhcHAvSmV3ZWxyeU1hbGwvbWluaXByb2dyYW0vY29tcG9uZW50cy9CYW5uZXJTd2lwZXIudnVl"],"sourcesContent":["\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n\r\n\r\n\r\n\r\n\r\n","import Component from 'F:/gitCode/uniapp/JewelryMall/miniprogram/components/BannerSwiper.vue'\nwx.createComponent(Component)"],"names":["BASE_URL"],"mappings":";;;;;;;;;;AAmBA,aAAS,QAAQ,MAAsB;AACrC,UAAI,CAAC;AAAa,eAAA;AACd,UAAA,KAAK,WAAW,MAAM;AAAU,eAAA;AACpC,aAAOA,cAAAA,WAAW;AAAA,IACpB;;;;;;;;;;;;;;;;;;ACtBA,GAAG,gBAAgB,SAAS;"}
\ No newline at end of file
diff --git a/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/components/ProductCard.js.map b/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/components/ProductCard.js.map
index 174dfd8b..ce7c233e 100644
--- a/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/components/ProductCard.js.map
+++ b/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/components/ProductCard.js.map
@@ -1 +1 @@
-{"version":3,"file":"ProductCard.js","sources":["components/ProductCard.vue","../../../../Software/HBuilderX.4.76.2025082103/HBuilderX/plugins/uniapp-cli-vite/uniComponent:/RjovZ2l0Q29kZS91bmlhcHAvSmV3ZWxyeU1hbGwvbWluaXByb2dyYW0vY29tcG9uZW50cy9Qcm9kdWN0Q2FyZC52dWU"],"sourcesContent":["\r\n \r\n \r\n \r\n {{ product.name }}\r\n 款号:{{ product.styleNo }}\r\n \r\n ¥{{ product.basePrice }}\r\n 库存 {{ product.stock }}\r\n \r\n \r\n \r\n\r\n\r\n\r\n\r\n\r\n","import Component from 'F:/gitCode/uniapp/JewelryMall/miniprogram/components/ProductCard.vue'\nwx.createComponent(Component)"],"names":["uni"],"mappings":";;;;;;;;AAqBA,UAAM,QAAQ;AAId,aAAS,WAAW;AACdA,0BAAA,WAAW,EAAE,KAAK,4BAA4B,MAAM,QAAQ,EAAE,IAAI;AAAA,IACxE;;;;;;;;;;;;;;AC1BA,GAAG,gBAAgB,SAAS;"}
\ No newline at end of file
+{"version":3,"file":"ProductCard.js","sources":["components/ProductCard.vue","../../../../Software/HBuilderX.4.76.2025082103/HBuilderX/plugins/uniapp-cli-vite/uniComponent:/RjovZ2l0Q29kZS91bmlhcHAvSmV3ZWxyeU1hbGwvbWluaXByb2dyYW0vY29tcG9uZW50cy9Qcm9kdWN0Q2FyZC52dWU"],"sourcesContent":["\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\t{{ product.name }}({{ product.styleNo }})\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t¥{{ product.basePrice }}\r\n\t\t\t\t\r\n\t\t\t\t库存{{ product.stock }}\r\n\t\t\t\r\n\t\t\r\n\t\r\n\r\n\r\n\r\n\r\n","import Component from 'F:/gitCode/uniapp/JewelryMall/miniprogram/components/ProductCard.vue'\nwx.createComponent(Component)"],"names":["BASE_URL","uni"],"mappings":";;;;;;;;;AAmBC,UAAM,QAAQ;AAEd,aAAS,SAAkB;;AAC1B,YAAM,MAAM,MAAM,QAAQ,WAAS,WAAM,QAAQ,iBAAd,mBAA6B;AAChE,UAAI,CAAC;AAAY,eAAA;AACb,UAAA,IAAI,WAAW,MAAM;AAAU,eAAA;AACnC,aAAOA,cAAAA,WAAW;AAAA,IACnB;AACA,aAAS,WAAW;AACfC,0BAAA,WAAW,EAAE,KAAK,4BAA4B,MAAM,QAAQ,EAAE,IAAI;AAAA,IACvE;;;;;;;;;;;;;;AC5BD,GAAG,gBAAgB,SAAS;"}
\ No newline at end of file
diff --git a/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/components/ShippingNotice.js.map b/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/components/ShippingNotice.js.map
index 0a731d22..0bf9fedd 100644
--- a/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/components/ShippingNotice.js.map
+++ b/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/components/ShippingNotice.js.map
@@ -1 +1 @@
-{"version":3,"file":"ShippingNotice.js","sources":["../../../../Software/HBuilderX.4.76.2025082103/HBuilderX/plugins/uniapp-cli-vite/uniComponent:/RjovZ2l0Q29kZS91bmlhcHAvSmV3ZWxyeU1hbGwvbWluaXByb2dyYW0vY29tcG9uZW50cy9TaGlwcGluZ05vdGljZS52dWU"],"sourcesContent":["import Component from 'F:/gitCode/uniapp/JewelryMall/miniprogram/components/ShippingNotice.vue'\nwx.createComponent(Component)"],"names":[],"mappings":";;;;;;;AACA,GAAG,gBAAgB,SAAS;"}
\ No newline at end of file
+{"version":3,"file":"ShippingNotice.js","sources":["../../../../Software/HBuilderX.4.76.2025082103/HBuilderX/plugins/uniapp-cli-vite/uniComponent:/RjovZ2l0Q29kZS91bmlhcHAvSmV3ZWxyeU1hbGwvbWluaXByb2dyYW0vY29tcG9uZW50cy9TaGlwcGluZ05vdGljZS52dWU"],"sourcesContent":["import Component from 'F:/gitCode/uniapp/JewelryMall/miniprogram/components/ShippingNotice.vue'\nwx.createComponent(Component)"],"names":[],"mappings":";;;;;;;;;;AACA,GAAG,gBAAgB,SAAS;"}
\ No newline at end of file
diff --git a/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/components/SpecPanel.js.map b/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/components/SpecPanel.js.map
index bd916579..048dd074 100644
--- a/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/components/SpecPanel.js.map
+++ b/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/components/SpecPanel.js.map
@@ -1 +1 @@
-{"version":3,"file":"SpecPanel.js","sources":["components/SpecPanel.vue","../../../../Software/HBuilderX.4.76.2025082103/HBuilderX/plugins/uniapp-cli-vite/uniComponent:/RjovZ2l0Q29kZS91bmlhcHAvSmV3ZWxyeU1hbGwvbWluaXByb2dyYW0vY29tcG9uZW50cy9TcGVjUGFuZWwudnVl"],"sourcesContent":["\r\n \r\n \r\n \r\n\r\n \r\n 加载中...\r\n\r\n \r\n \r\n \r\n 成色\r\n \r\n \r\n {{ item }}\r\n \r\n \r\n \r\n\r\n \r\n \r\n 主石\r\n \r\n \r\n {{ item }}\r\n \r\n \r\n \r\n\r\n \r\n \r\n 手寸\r\n \r\n \r\n {{ item }}\r\n \r\n \r\n \r\n\r\n \r\n \r\n \r\n 查询规格数据\r\n \r\n \r\n\r\n \r\n 查询中...\r\n \r\n \r\n \r\n 型号\r\n {{ spec.modelName }}\r\n \r\n \r\n 金料总重\r\n {{ spec.goldTotalWeight }}g\r\n \r\n \r\n 金值\r\n ¥{{ spec.goldValue }}\r\n \r\n \r\n 主石金额\r\n ¥{{ spec.mainStoneAmount }}\r\n \r\n \r\n 副石金额\r\n ¥{{ spec.sideStoneAmount }}\r\n \r\n \r\n 总工费\r\n ¥{{ spec.totalLaborCost }}\r\n \r\n \r\n 总价\r\n ¥{{ spec.totalPrice }}\r\n \r\n \r\n \r\n \r\n \r\n \r\n\r\n\r\n\r\n\r\n\r\n","import Component from 'F:/gitCode/uniapp/JewelryMall/miniprogram/components/SpecPanel.vue'\nwx.createComponent(Component)"],"names":["ref","reactive","computed","onMounted","getProductSpecs","getSpecDataList"],"mappings":";;;;;;;;;;AAmHA,UAAM,QAAQ;AAQR,UAAA,SAASA,kBAAkC,IAAI;AAC/C,UAAA,gBAAgBA,kBAAI,KAAK;AACzB,UAAA,cAAcA,kBAAI,KAAK;AACvB,UAAA,eAAeA,kBAAgB,CAAA,CAAE;AAEvC,UAAM,WAAWC,cAAAA,SAAS;AAAA,MACxB,UAAU;AAAA,MACV,WAAW;AAAA,MACX,UAAU;AAAA,IAAA,CACX;AAED,UAAM,WAAWC,cAAA;AAAA,MAAS,MACxB,SAAS,YAAY,SAAS,aAAa,SAAS;AAAA,IAAA;AAGtDC,kBAAAA,UAAU,YAAY;AACpB,oBAAc,QAAQ;AAClB,UAAA;AACF,eAAO,QAAQ,MAAMC,YAAgB,gBAAA,MAAM,SAAS;AAAA,MAAA,QAC9C;AAAA,MAAA,UAEN;AACA,sBAAc,QAAQ;AAAA,MACxB;AAAA,IAAA,CACD;AAED,mBAAe,gBAAgB;AAC7B,UAAI,CAAC,SAAS;AAAO;AACrB,kBAAY,QAAQ;AAChB,UAAA;AACF,qBAAa,QAAQ,MAAMC,4BAAgB,MAAM,WAAW;AAAA,UAC1D,UAAU,SAAS;AAAA,UACnB,WAAW,SAAS;AAAA,UACpB,UAAU,SAAS;AAAA,QAAA,CACpB;AAAA,MAAA,QACK;AAAA,MAAA,UAEN;AACA,oBAAY,QAAQ;AAAA,MACtB;AAAA,IACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClKA,GAAG,gBAAgB,SAAS;"}
\ No newline at end of file
+{"version":3,"file":"SpecPanel.js","sources":["components/SpecPanel.vue","../../../../Software/HBuilderX.4.76.2025082103/HBuilderX/plugins/uniapp-cli-vite/uniComponent:/RjovZ2l0Q29kZS91bmlhcHAvSmV3ZWxyeU1hbGwvbWluaXByb2dyYW0vY29tcG9uZW50cy9TcGVjUGFuZWwudnVl"],"sourcesContent":["\r\n \r\n \r\n \r\n \r\n \r\n 加载中...\r\n\r\n \r\n \r\n \r\n 成 色\r\n \r\n {{ item }}\r\n \r\n \r\n\r\n \r\n \r\n 主 石\r\n \r\n {{ item }}\r\n \r\n \r\n\r\n \r\n \r\n 手 寸\r\n \r\n {{ item }}\r\n \r\n \r\n \r\n\r\n \r\n 查询中...\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n 型号名称\r\n {{ spec.modelName }}\r\n \r\n \r\n 金料总重\r\n {{ spec.goldTotalWeight }}g\r\n \r\n \r\n 金料净重\r\n {{ spec.goldNetWeight }}g\r\n \r\n \r\n 金耗\r\n {{ spec.goldLoss }}g\r\n \r\n \r\n 金值\r\n ¥{{ spec.goldValue }}\r\n \r\n \r\n 主石数量\r\n {{ spec.mainStoneCount }}粒\r\n \r\n \r\n 主石石重\r\n {{ spec.mainStoneWeight }}ct\r\n \r\n \r\n 主石单价\r\n ¥{{ spec.mainStoneUnitPrice }}\r\n \r\n \r\n 主石金额\r\n ¥{{ spec.mainStoneAmount }}\r\n \r\n \r\n 配件金额\r\n ¥{{ spec.accessoryAmount }}\r\n \r\n \r\n 总工费\r\n ¥{{ spec.totalLaborCost }}\r\n \r\n \r\n \r\n \r\n 成色\r\n {{ spec.fineness }}\r\n \r\n \r\n 损耗\r\n {{ spec.loss }}%\r\n \r\n \r\n 主石\r\n {{ spec.mainStone }}\r\n \r\n \r\n 手寸\r\n {{ spec.ringSize }}\r\n \r\n \r\n 金价\r\n ¥{{ spec.goldPrice }}\r\n \r\n \r\n 副石数量\r\n {{ spec.sideStoneCount }}粒\r\n \r\n \r\n 副石石重\r\n {{ spec.sideStoneWeight }}ct\r\n \r\n \r\n 副石单价\r\n ¥{{ spec.sideStoneUnitPrice }}\r\n \r\n \r\n 副石金额\r\n ¥{{ spec.sideStoneAmount }}\r\n \r\n \r\n 加工工费\r\n ¥{{ spec.processingFee }}\r\n \r\n \r\n 镶石工费\r\n ¥{{ spec.settingFee }}\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n\r\n \r\n \r\n \r\n 加入购物车({{ selectedSpecs.size }})\r\n \r\n \r\n \r\n \r\n\r\n\r\n\r\n\r\n\r\n","import Component from 'F:/gitCode/uniapp/JewelryMall/miniprogram/components/SpecPanel.vue'\nwx.createComponent(Component)"],"names":["ref","useCartStore","reactive","uni","onMounted","getProductSpecs","getSpecDataList"],"mappings":";;;;;;;;;;;AA6KA,UAAM,QAAQ;AACd,UAAM,OAAO;AAEP,UAAA,SAASA,kBAAkC,IAAI;AAC/C,UAAA,gBAAgBA,kBAAI,KAAK;AACzB,UAAA,cAAcA,kBAAI,KAAK;AACvB,UAAA,eAAeA,kBAAgB,CAAA,CAAE;AACvC,UAAM,gBAAgBA,cAAAA,IAA+B,oBAAA,IAAK,CAAA;AAC1D,UAAM,YAAYC,WAAAA;AAEZ,UAAA,WAAWC,uBAAS,EAAE,UAAU,IAAI,WAAW,IAAI,UAAU,GAAA,CAAI;AAE9D,aAAA,aAAa,KAA4C,MAAc;AAC9E,eAAS,GAAG,IAAI,SAAS,GAAG,MAAM,OAAO,KAAK;AAC9C,UAAI,SAAS,YAAY,SAAS,aAAa,SAAS,UAAU;AAClD;MAAA,OACT;AACL,qBAAa,QAAQ;MACvB;AAAA,IACF;AAEA,aAAS,aAAa,MAAgB;AACpC,UAAI,cAAc,MAAM,IAAI,KAAK,EAAE,GAAG;AACtB,sBAAA,MAAM,OAAO,KAAK,EAAE;AAAA,MAAA,OAC7B;AACL,sBAAc,MAAM,IAAI,KAAK,IAAI,IAAI;AAAA,MACvC;AACA,oBAAc,QAAQ,IAAI,IAAI,cAAc,KAAK;AAAA,IACnD;AAEA,aAAS,kBAAkB;AACrB,UAAA,cAAc,MAAM,SAAS;AAAG;AACtB,oBAAA,MAAM,QAAQ,CAAC,SAAS;AACpC,kBAAU,UAAU;AAAA,UAClB,IAAI,KAAK,IAAI,IAAI,KAAK;AAAA,UACtB,QAAQ;AAAA,UACR,WAAW,MAAM;AAAA,UACjB,YAAY,KAAK;AAAA,UACjB,UAAU;AAAA,UACV,SAAS,CAAC;AAAA,UACV,UAAU;AAAA,UACV,SAAS;AAAA,QAAA,CACV;AAAA,MAAA,CACF;AACGC,oBAAAA,MAAA,UAAU,EAAE,OAAO,MAAM,cAAc,MAAM,IAAI,KAAK,MAAM,UAAW,CAAA;AAC7D,oBAAA,4BAAY;AAC1B,WAAK,OAAO;AAAA,IACd;AAEAC,kBAAAA,UAAU,YAAY;AACpB,oBAAc,QAAQ;AAClB,UAAA;AAAE,eAAO,QAAQ,MAAMC,YAAgB,gBAAA,MAAM,SAAS;AAAA,MAAA,QACpD;AAAA,MAAA,UACN;AAAU,sBAAc,QAAQ;AAAA,MAAM;AAAA,IAAA,CACvC;AAED,mBAAe,gBAAgB;AAC7B,kBAAY,QAAQ;AAChB,UAAA;AACF,qBAAa,QAAQ,MAAMC,4BAAgB,MAAM,WAAW;AAAA,UAC1D,UAAU,SAAS,YAAY;AAAA,UAC/B,WAAW,SAAS,aAAa;AAAA,UACjC,UAAU,SAAS,YAAY;AAAA,QAAA,CAChC;AAAA,MAAA,QACK;AAAA,MAAA,UACR;AAAU,oBAAY,QAAQ;AAAA,MAAM;AAAA,IACtC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9OA,GAAG,gBAAgB,SAAS;"}
\ No newline at end of file
diff --git a/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/pages/index/index.js.map b/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/pages/index/index.js.map
index f7a7afe2..e09e7b60 100644
--- a/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/pages/index/index.js.map
+++ b/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/pages/index/index.js.map
@@ -1 +1 @@
-{"version":3,"file":"index.js","sources":["pages/index/index.vue","../../../../Software/HBuilderX.4.76.2025082103/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvaW5kZXgvaW5kZXgudnVl"],"sourcesContent":["\r\n \r\n \r\n \r\n \r\n {{ cat.name }}\r\n \r\n \r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n\r\n \r\n \r\n 暂无商品\r\n \r\n\r\n \r\n \r\n 加载中...\r\n \r\n \r\n\r\n\r\n\r\n\r\n\r\n","import MiniProgramPage from 'F:/gitCode/uniapp/JewelryMall/miniprogram/pages/index/index.vue'\nwx.createPage(MiniProgramPage)"],"names":["ref","getCategories","getProducts","onMounted"],"mappings":";;;;;;AAsCA,MAAA,cAAwB,MAAA;AAOxB,MAAM,WAAW;;;;AALX,UAAA,WAAWA,kBAAe,CAAA,CAAE;AAC5B,UAAA,aAAaA,kBAAgB,CAAA,CAAE;AAC/B,UAAA,mBAAmBA,cAAAA,IAAwB,MAAS;AACpD,UAAA,UAAUA,kBAAI,KAAK;AACnB,UAAA,OAAOA,kBAAI,CAAC;AAGlB,mBAAe,iBAAiB;AAC1B,UAAA;AACI,cAAA,OAAO,MAAMC,YAAAA;AACR,mBAAA,QAAQ,CAAC,EAAE,IAAI,GAAG,MAAM,MAAM,MAAM,KAAiB,GAAG,IAAI;AAAA,MAAA,QACjE;AAAA,MAER;AAAA,IACF;AAEe,mBAAA,aAAa,QAAQ,OAAO;AACzC,UAAI,OAAO;AACT,aAAK,QAAQ;AACb,iBAAS,QAAQ;MACnB;AACA,cAAQ,QAAQ;AACZ,UAAA;AACF,cAAM,SAAkC,EAAE,MAAM,KAAK,OAAO,SAAS;AACrE,YAAI,iBAAiB,SAAS,iBAAiB,UAAU,GAAG;AAC1D,iBAAO,aAAa,iBAAiB;AAAA,QACvC;AACM,cAAA,OAAO,MAAMC,wBAAY,MAAmE;AAClG,YAAI,OAAO;AACT,mBAAS,QAAQ,KAAK;AAAA,QAAA,OACjB;AACL,mBAAS,MAAM,KAAK,GAAG,KAAK,IAAI;AAAA,QAClC;AAAA,MAAA,QACM;AAAA,MAAA,UAEN;AACA,gBAAQ,QAAQ;AAAA,MAClB;AAAA,IACF;AAEA,aAAS,eAAe,IAAY;AAClC,uBAAiB,QAAQ;AACzB,mBAAa,IAAI;AAAA,IACnB;AAEAC,kBAAAA,UAAU,MAAM;AACC;AACf,mBAAa,IAAI;AAAA,IAAA,CAClB;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACvFD,GAAG,WAAW,eAAe;"}
\ No newline at end of file
+{"version":3,"file":"index.js","sources":["pages/index/index.vue","../../../../Software/HBuilderX.4.76.2025082103/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvaW5kZXgvaW5kZXgudnVl"],"sourcesContent":["\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\t凯缘钻之城\r\n\t\t\t\r\n\t\t\r\n\r\n\t\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t请输入产品名称、款号、条码号或款式\r\n\t\t\t\r\n\t\t\t搜索\r\n\t\t\r\n\r\n\t\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t💎\r\n\t\t\t\t\t\r\n\t\t\t\t\t{{ cat.name }}\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\r\n\t\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\t💎\r\n\t\t\t\t钻戒计算器\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t👩💼\r\n\t\t\t\t客服找款\r\n\t\t\t\r\n\t\t\r\n\r\n\t\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\r\n\t\t\r\n\t\t\r\n\t\t\t暂无商品\r\n\t\t\r\n\r\n\t\t\r\n\t\t\r\n\t\t\t加载中...\r\n\t\t\r\n\r\n\t\t\r\n\t\t\r\n\t\r\n\r\n\r\n\r\n\r\n","import MiniProgramPage from 'F:/gitCode/uniapp/JewelryMall/miniprogram/pages/index/index.vue'\nwx.createPage(MiniProgramPage)"],"names":["ref","uni","BASE_URL","getCategories","getProducts","onMounted"],"mappings":";;;;;;;;AAuEC,MAAA,cAAwB,MAAA;AACxB,MAAA,qBAA+B,MAAA;AAS/B,MAAM,WAAW;;;;AAPX,UAAA,WAAWA,kBAAe,CAAA,CAAE;AAC5B,UAAA,aAAaA,kBAAgB,CAAA,CAAE;AAC/B,UAAA,mBAAmBA,cAAAA,IAAwB,MAAS;AACpD,UAAA,UAAUA,kBAAI,KAAK;AACnB,UAAA,aAAaA,kBAAI,KAAK;AACtB,UAAA,OAAOA,kBAAI,CAAC;AACZ,UAAA,UAAUA,kBAAI,EAAE;AAIhB,UAAA,kBAAkBA,kBAAI,EAAE;AACxB,UAAA,eAAeA,kBAAI,EAAE;AAEvB,QAAA;AACG,YAAA,UAAUC,oBAAI;AACJ,sBAAA,QAAQ,QAAQ,mBAAmB;AAE7C,YAAA,UAAUA,oBAAI;AACpB,mBAAa,SAAS,QAAQ,OAAO,QAAQ,mBAAmB,OAAO,IAAI,QAAQ;AAAA,IAAA,QAE5E;AAAA,IAAiB;AAEzB,aAAS,QAAQ,MAAwB;AACxC,UAAI,CAAC;AAAa,eAAA;AACd,UAAA,KAAK,WAAW,MAAM;AAAU,eAAA;AACpC,aAAOC,cAAAA,WAAW;AAAA,IACnB;AAEA,mBAAe,iBAAiB;AAC3B,UAAA;AACG,cAAA,OAAO,MAAMC,YAAAA;AACnB,mBAAW,QAAQ;AAAA,MAAA,QACZ;AAAA,MAAgB;AAAA,IACzB;AAEe,mBAAA,aAAa,QAAQ,OAAO;AAC1C,UAAI,OAAO;AAAE,aAAK,QAAQ;AAAG,iBAAS,QAAQ;MAAG;AACjD,cAAQ,QAAQ;AACZ,UAAA;AACH,cAAM,SAAmC,EAAE,MAAM,KAAK,OAAO,SAAS;AACtE,YAAI,iBAAiB;AAAO,iBAAO,aAAa,iBAAiB;AACjE,YAAI,QAAQ;AAAO,iBAAO,UAAU,QAAQ;AACtC,cAAA,OAAO,MAAMC,wBAAY,MAAa;AAC5C,YAAI,OAAO;AAAE,mBAAS,QAAQ,KAAK;AAAA,QAAA,OAAY;AAAE,mBAAS,MAAM,KAAK,GAAG,KAAK,IAAI;AAAA,QAAE;AAAA,MAAA,QAC5E;AAAA,MAAA,UACR;AAAU,gBAAQ,QAAQ;AAAA,MAAM;AAAA,IACjC;AAEA,aAAS,eAAe,IAAa;AACpC,uBAAiB,QAAQ,iBAAiB,UAAU,KAAK,SAAY;AACrE,mBAAa,IAAI;AAAA,IAClB;AAEA,aAAS,WAAW;AAAA,IAEpB;AAEA,aAAS,eAAe;AACvBH,oBAAAA,MAAI,WAAW,EAAE,KAAK,0BAA2B,CAAA;AAAA,IAClD;AAEAI,kBAAAA,UAAU,MAAM;AAAiB;AAAG,mBAAa,IAAI;AAAA,IAAA,CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtIzD,GAAG,WAAW,eAAe;"}
\ No newline at end of file
diff --git a/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/pages/product/detail.js.map b/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/pages/product/detail.js.map
index 2d1877c2..7ca4c7b6 100644
--- a/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/pages/product/detail.js.map
+++ b/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/pages/product/detail.js.map
@@ -1 +1 @@
-{"version":3,"file":"detail.js","sources":["pages/product/detail.vue","../../../../Software/HBuilderX.4.76.2025082103/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvcHJvZHVjdC9kZXRhaWwudnVl"],"sourcesContent":["\r\n \r\n \r\n \r\n\r\n \r\n \r\n ¥{{ product.basePrice }}\r\n {{ product.name }}\r\n \r\n \r\n 款号\r\n {{ product.styleNo }}\r\n \r\n \r\n 库存\r\n {{ product.stock }}\r\n \r\n \r\n 损耗\r\n {{ product.loss }}\r\n \r\n \r\n 工费\r\n ¥{{ product.laborCost }}\r\n \r\n \r\n \r\n\r\n \r\n \r\n\r\n \r\n \r\n 查看详细参数\r\n ›\r\n \r\n\r\n \r\n \r\n\r\n \r\n \r\n 客服\r\n 加入购物车\r\n \r\n\r\n \r\n \r\n \r\n\r\n\r\n\r\n\r\n\r\n","import MiniProgramPage from 'F:/gitCode/uniapp/JewelryMall/miniprogram/pages/product/detail.vue'\nwx.createPage(MiniProgramPage)"],"names":["ref","useCartStore","onMounted","getProductDetail","uni"],"mappings":";;;;;;;AA6DA,MAAA,eAAyB,MAAA;AACzB,MAAA,iBAA2B,MAAA;AAC3B,MAAA,YAAsB,MAAA;AACtB,MAAA,qBAA+B,MAAA;;;;AAEzB,UAAA,UAAUA,kBAAoB,IAAI;AAClC,UAAA,gBAAgBA,kBAAI,KAAK;AACzB,UAAA,aAAaA,kBAAI,KAAK;AAC5B,UAAM,YAAYC,WAAAA;AAElBC,kBAAAA,UAAU,MAAM;;AACd,YAAM,QAAQ;AACd,YAAM,cAAc,MAAM,MAAM,SAAS,CAAC;AAC1C,YAAM,KAAK,QAAO,iBAAY,YAAZ,mBAAqB,EAAE;AACzC,UAAI,IAAI;AACN,oBAAY,EAAE;AAAA,MAChB;AAAA,IAAA,CACD;AAED,mBAAe,YAAY,IAAY;AACjC,UAAA;AACM,gBAAA,QAAQ,MAAMC,YAAA,iBAAiB,EAAE;AAAA,MAAA,QACnC;AACNC,sBAAA,MAAI,UAAU,EAAE,OAAO,UAAU,MAAM,QAAQ;AAAA,MACjD;AAAA,IACF;AAEA,aAAS,kBAAkB;AACzB,UAAI,CAAC,QAAQ;AAAO;AACpB,YAAM,OAAiB;AAAA,QACrB,IAAI,KAAK,IAAI;AAAA,QACb,QAAQ;AAAA,QACR,WAAW,QAAQ,MAAM;AAAA,QACzB,YAAY;AAAA,QACZ,UAAU;AAAA,QACV,SAAS,QAAQ;AAAA,QACjB,UAAU;AAAA,UACR,IAAI;AAAA,UACJ,WAAW,QAAQ,MAAM;AAAA,UACzB,WAAW,QAAQ,MAAM;AAAA,UACzB,UAAU;AAAA,UACV,WAAW;AAAA,UACX,UAAU;AAAA,UACV,iBAAiB;AAAA,UACjB,eAAe;AAAA,UACf,MAAM;AAAA,UACN,UAAU;AAAA,UACV,WAAW;AAAA,UACX,WAAW;AAAA,UACX,gBAAgB;AAAA,UAChB,iBAAiB;AAAA,UACjB,oBAAoB;AAAA,UACpB,iBAAiB;AAAA,UACjB,gBAAgB;AAAA,UAChB,iBAAiB;AAAA,UACjB,oBAAoB;AAAA,UACpB,iBAAiB;AAAA,UACjB,iBAAiB;AAAA,UACjB,eAAe;AAAA,UACf,YAAY;AAAA,UACZ,gBAAgB;AAAA,UAChB,YAAY,QAAQ,MAAM;AAAA,QAC5B;AAAA,QACA,SAAS;AAAA,MAAA;AAEX,gBAAU,UAAU,IAAI;AACxBA,oBAAA,MAAI,UAAU,EAAE,OAAO,UAAU,MAAM,WAAW;AAAA,IACpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/HA,GAAG,WAAW,eAAe;"}
\ No newline at end of file
+{"version":3,"file":"detail.js","sources":["pages/product/detail.vue","../../../../Software/HBuilderX.4.76.2025082103/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvcHJvZHVjdC9kZXRhaWwudnVl"],"sourcesContent":["\r\n \r\n \r\n \r\n \r\n \r\n 商品详情\r\n \r\n \r\n \r\n\r\n \r\n \r\n\r\n \r\n \r\n \r\n \r\n\r\n \r\n \r\n \r\n {{ product.name }}\r\n \r\n ¥\r\n {{ product.basePrice }}\r\n 元\r\n \r\n \r\n \r\n \r\n 款 号\r\n {{ product.styleNo }}\r\n 库存\r\n {{ product.stock }}\r\n \r\n \r\n 损 耗\r\n {{ product.loss }}%\r\n 工费\r\n ¥{{ product.laborCost }}\r\n \r\n \r\n \r\n\r\n \r\n \r\n\r\n \r\n \r\n 商品详情\r\n \r\n \r\n \r\n \r\n\r\n \r\n \r\n \r\n \r\n \r\n 客服\r\n \r\n \r\n \r\n 购物车\r\n \r\n \r\n \r\n 空托—查看详细参数\r\n \r\n \r\n\r\n \r\n \r\n\r\n \r\n \r\n \r\n\r\n\r\n\r\n\r\n\r\n","import MiniProgramPage from 'F:/gitCode/uniapp/JewelryMall/miniprogram/pages/product/detail.vue'\nwx.createPage(MiniProgramPage)"],"names":["ref","uni","BASE_URL","onMounted","getProductDetail"],"mappings":";;;;;;;;AA4FA,MAAA,eAAyB,MAAA;AACzB,MAAA,iBAA2B,MAAA;AAC3B,MAAA,YAAsB,MAAA;AACtB,MAAA,qBAA+B,MAAA;;;;AAEzB,UAAA,UAAUA,kBAAoB,IAAI;AAClC,UAAA,gBAAgBA,kBAAI,KAAK;AACzB,UAAA,aAAaA,kBAAI,KAAK;AAEtB,UAAA,kBAAkBA,kBAAI,EAAE;AACxB,UAAA,eAAeA,kBAAI,EAAE;AACvB,QAAA;AACI,YAAA,UAAUC,oBAAI;AACJ,sBAAA,QAAQ,QAAQ,mBAAmB;AAE7C,YAAA,UAAUA,oBAAI;AACpB,mBAAa,SAAS,QAAQ,OAAO,QAAQ,mBAAmB,OAAO,IAAI,QAAQ;AAAA,IAAA,QAE7E;AAAA,IAAiB;AAEzB,aAAS,SAAS;AAChBA,oBAAAA,MAAI,aAAa,EAAE,OAAO,EAAG,CAAA;AAAA,IAC/B;AAEA,aAAS,QAAQ,MAAsB;AACrC,UAAI,CAAC;AAAa,eAAA;AACd,UAAA,KAAK,WAAW,MAAM;AAAU,eAAA;AACpC,aAAOC,cAAAA,WAAW;AAAA,IACpB;AAEA,aAAS,SAAS;AAChBD,oBAAAA,MAAI,UAAU,EAAE,KAAK,oBAAqB,CAAA;AAAA,IAC5C;AAEAE,kBAAAA,UAAU,MAAM;;AACd,YAAM,QAAQ;AACd,YAAM,cAAc,MAAM,MAAM,SAAS,CAAC;AAC1C,YAAM,KAAK,QAAO,iBAAY,YAAZ,mBAAqB,EAAE;AACrC,UAAA;AAAI,oBAAY,EAAE;AAAA,IAAA,CACvB;AAED,mBAAe,YAAY,IAAY;AACjC,UAAA;AACM,gBAAA,QAAQ,MAAMC,YAAA,iBAAiB,EAAE;AAAA,MAAA,QACnC;AACNH,sBAAA,MAAI,UAAU,EAAE,OAAO,UAAU,MAAM,QAAQ;AAAA,MACjD;AAAA,IACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1IA,GAAG,WAAW,eAAe;"}
\ No newline at end of file
diff --git a/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/store/cart.js.map b/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/store/cart.js.map
index eaea4b31..d3770449 100644
--- a/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/store/cart.js.map
+++ b/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/store/cart.js.map
@@ -1 +1 @@
-{"version":3,"file":"cart.js","sources":["store/cart.ts"],"sourcesContent":["import { defineStore } from 'pinia'\r\nimport { ref, computed } from 'vue'\r\nimport type { CartItem } from '../types'\r\n\r\nexport const useCartStore = defineStore('cart', () => {\r\n const items = ref([])\r\n\r\n /** 已勾选的商品 */\r\n const checkedItems = computed(() => items.value.filter((item) => item.checked))\r\n\r\n /** 已勾选商品总金额 */\r\n const totalAmount = computed(() =>\r\n checkedItems.value.reduce((sum, item) => sum + item.specData.totalPrice * item.quantity, 0),\r\n )\r\n\r\n /** 从后端拉取购物车列表并同步到本地 */\r\n async function fetchCart() {\r\n try {\r\n const { getCartList } = await import('../api/cart')\r\n const list = await getCartList()\r\n items.value = list.map((item) => ({ ...item, checked: true }))\r\n } catch {\r\n // 未登录或网络异常,保留本地数据\r\n }\r\n }\r\n\r\n /** 添加商品到购物车(本地优先,后台同步) */\r\n function addToCart(item: CartItem) {\r\n items.value.push(item)\r\n // 异步同步到后端\r\n import('../api/cart').then(({ addToCart: apiAdd }) => {\r\n apiAdd({\r\n productId: item.productId,\r\n specDataId: item.specDataId,\r\n quantity: item.quantity,\r\n }).catch(() => { /* 静默处理 */ })\r\n }).catch(() => { /* 静默处理 */ })\r\n }\r\n\r\n /** 移除购物车项 */\r\n function removeFromCart(id: number) {\r\n const index = items.value.findIndex((item) => item.id === id)\r\n if (index !== -1) {\r\n items.value.splice(index, 1)\r\n import('../api/cart').then(({ deleteCartItem }) => {\r\n deleteCartItem(id).catch(() => { /* 静默处理 */ })\r\n }).catch(() => { /* 静默处理 */ })\r\n }\r\n }\r\n\r\n /** 更新数量 */\r\n function updateQuantity(id: number, quantity: number) {\r\n const item = items.value.find((item) => item.id === id)\r\n if (item) {\r\n item.quantity = quantity\r\n import('../api/cart').then(({ updateCartItem }) => {\r\n updateCartItem(id, { quantity }).catch(() => { /* 静默处理 */ })\r\n }).catch(() => { /* 静默处理 */ })\r\n }\r\n }\r\n\r\n /** 切换勾选状态(纯本地操作) */\r\n function toggleCheck(id: number) {\r\n const item = items.value.find((item) => item.id === id)\r\n if (item) {\r\n item.checked = !item.checked\r\n }\r\n }\r\n\r\n /** 全选/取消全选(纯本地操作) */\r\n function toggleCheckAll() {\r\n const allChecked = items.value.every((item) => item.checked)\r\n items.value.forEach((item) => {\r\n item.checked = !allChecked\r\n })\r\n }\r\n\r\n return {\r\n items,\r\n checkedItems,\r\n totalAmount,\r\n fetchCart,\r\n addToCart,\r\n removeFromCart,\r\n updateQuantity,\r\n toggleCheck,\r\n toggleCheckAll,\r\n }\r\n})\r\n"],"names":["defineStore","ref","computed","item"],"mappings":";;AAIa,MAAA,eAAeA,cAAAA,YAAY,QAAQ,MAAM;AAC9C,QAAA,QAAQC,kBAAgB,CAAA,CAAE;AAG1B,QAAA,eAAeC,cAAAA,SAAS,MAAM,MAAM,MAAM,OAAO,CAAC,SAAS,KAAK,OAAO,CAAC;AAG9E,QAAM,cAAcA,cAAA;AAAA,IAAS,MAC3B,aAAa,MAAM,OAAO,CAAC,KAAK,SAAS,MAAM,KAAK,SAAS,aAAa,KAAK,UAAU,CAAC;AAAA,EAAA;AAI5F,iBAAe,YAAY;AACrB,QAAA;AACF,YAAM,EAAE,YAAA,IAAgB,MAAa;AAC/B,YAAA,OAAO,MAAM;AACb,YAAA,QAAQ,KAAK,IAAI,CAAC,UAAU,EAAE,GAAG,MAAM,SAAS,KAAA,EAAO;AAAA,IAAA,QACvD;AAAA,IAER;AAAA,EACF;AAGA,WAAS,UAAU,MAAgB;AAC3B,UAAA,MAAM,KAAK,IAAI;AAErB,IAAO,iBAAe,KAAK,CAAC,EAAE,WAAW,aAAa;AAC7C,aAAA;AAAA,QACL,WAAW,KAAK;AAAA,QAChB,YAAY,KAAK;AAAA,QACjB,UAAU,KAAK;AAAA,MAAA,CAChB,EAAE,MAAM,MAAM;AAAA,MAAA,CAAc;AAAA,IAAA,CAC9B,EAAE,MAAM,MAAM;AAAA,IAAA,CAAc;AAAA,EAC/B;AAGA,WAAS,eAAe,IAAY;AAC5B,UAAA,QAAQ,MAAM,MAAM,UAAU,CAAC,SAAS,KAAK,OAAO,EAAE;AAC5D,QAAI,UAAU,IAAI;AACV,YAAA,MAAM,OAAO,OAAO,CAAC;AAC3B,MAAO,iBAAe,KAAK,CAAC,EAAE,qBAAqB;AAClC,uBAAA,EAAE,EAAE,MAAM,MAAM;AAAA,QAAA,CAAc;AAAA,MAAA,CAC9C,EAAE,MAAM,MAAM;AAAA,MAAA,CAAc;AAAA,IAC/B;AAAA,EACF;AAGS,WAAA,eAAe,IAAY,UAAkB;AAC9C,UAAA,OAAO,MAAM,MAAM,KAAK,CAACC,UAASA,MAAK,OAAO,EAAE;AACtD,QAAI,MAAM;AACR,WAAK,WAAW;AAChB,MAAO,iBAAe,KAAK,CAAC,EAAE,qBAAqB;AACjD,uBAAe,IAAI,EAAE,SAAA,CAAU,EAAE,MAAM,MAAM;AAAA,QAAA,CAAc;AAAA,MAAA,CAC5D,EAAE,MAAM,MAAM;AAAA,MAAA,CAAc;AAAA,IAC/B;AAAA,EACF;AAGA,WAAS,YAAY,IAAY;AACzB,UAAA,OAAO,MAAM,MAAM,KAAK,CAACA,UAASA,MAAK,OAAO,EAAE;AACtD,QAAI,MAAM;AACH,WAAA,UAAU,CAAC,KAAK;AAAA,IACvB;AAAA,EACF;AAGA,WAAS,iBAAiB;AACxB,UAAM,aAAa,MAAM,MAAM,MAAM,CAAC,SAAS,KAAK,OAAO;AACrD,UAAA,MAAM,QAAQ,CAAC,SAAS;AAC5B,WAAK,UAAU,CAAC;AAAA,IAAA,CACjB;AAAA,EACH;AAEO,SAAA;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEJ,CAAC;;"}
\ No newline at end of file
+{"version":3,"file":"cart.js","sources":["store/cart.ts"],"sourcesContent":["import { defineStore } from 'pinia'\r\nimport { ref, computed } from 'vue'\r\nimport type { CartItem } from '../types'\r\nimport { getCartList, addToCart as apiAddToCart, deleteCartItem as apiDeleteCartItem, updateCartItem as apiUpdateCartItem } from '../api/cart'\r\n\r\nexport const useCartStore = defineStore('cart', () => {\r\n const items = ref([])\r\n\r\n const checkedItems = computed(() => items.value.filter((item) => item.checked))\r\n\r\n const totalAmount = computed(() =>\r\n checkedItems.value.reduce((sum, item) => sum + item.specData.totalPrice * item.quantity, 0),\r\n )\r\n\r\n async function fetchCart() {\r\n try {\r\n const list = await getCartList()\r\n items.value = list.map((item) => ({ ...item, checked: true }))\r\n } catch {\r\n // 未登录或网络异常,保留本地数据\r\n }\r\n }\r\n\r\n function addToCart(item: CartItem) {\r\n items.value.push(item)\r\n apiAddToCart({\r\n productId: item.productId,\r\n specDataId: item.specDataId,\r\n quantity: item.quantity,\r\n }).catch(() => { /* 静默处理 */ })\r\n }\r\n\r\n function removeFromCart(id: number) {\r\n const index = items.value.findIndex((item) => item.id === id)\r\n if (index !== -1) {\r\n items.value.splice(index, 1)\r\n apiDeleteCartItem(id).catch(() => { /* 静默处理 */ })\r\n }\r\n }\r\n\r\n function updateQuantity(id: number, quantity: number) {\r\n const item = items.value.find((item) => item.id === id)\r\n if (item) {\r\n item.quantity = quantity\r\n apiUpdateCartItem(id, { quantity }).catch(() => { /* 静默处理 */ })\r\n }\r\n }\r\n\r\n /** 切换勾选状态(纯本地操作) */\r\n function toggleCheck(id: number) {\r\n const item = items.value.find((item) => item.id === id)\r\n if (item) {\r\n item.checked = !item.checked\r\n }\r\n }\r\n\r\n /** 全选/取消全选(纯本地操作) */\r\n function toggleCheckAll() {\r\n const allChecked = items.value.every((item) => item.checked)\r\n items.value.forEach((item) => {\r\n item.checked = !allChecked\r\n })\r\n }\r\n\r\n return {\r\n items,\r\n checkedItems,\r\n totalAmount,\r\n fetchCart,\r\n addToCart,\r\n removeFromCart,\r\n updateQuantity,\r\n toggleCheck,\r\n toggleCheckAll,\r\n }\r\n})\r\n"],"names":["defineStore","ref","computed","getCartList","apiAddToCart","apiDeleteCartItem","item","apiUpdateCartItem"],"mappings":";;;AAKa,MAAA,eAAeA,cAAAA,YAAY,QAAQ,MAAM;AAC9C,QAAA,QAAQC,kBAAgB,CAAA,CAAE;AAE1B,QAAA,eAAeC,cAAAA,SAAS,MAAM,MAAM,MAAM,OAAO,CAAC,SAAS,KAAK,OAAO,CAAC;AAE9E,QAAM,cAAcA,cAAA;AAAA,IAAS,MAC3B,aAAa,MAAM,OAAO,CAAC,KAAK,SAAS,MAAM,KAAK,SAAS,aAAa,KAAK,UAAU,CAAC;AAAA,EAAA;AAG5F,iBAAe,YAAY;AACrB,QAAA;AACI,YAAA,OAAO,MAAMC,SAAAA;AACb,YAAA,QAAQ,KAAK,IAAI,CAAC,UAAU,EAAE,GAAG,MAAM,SAAS,KAAA,EAAO;AAAA,IAAA,QACvD;AAAA,IAER;AAAA,EACF;AAEA,WAAS,UAAU,MAAgB;AAC3B,UAAA,MAAM,KAAK,IAAI;AACRC,uBAAA;AAAA,MACX,WAAW,KAAK;AAAA,MAChB,YAAY,KAAK;AAAA,MACjB,UAAU,KAAK;AAAA,IAAA,CAChB,EAAE,MAAM,MAAM;AAAA,IAAA,CAAc;AAAA,EAC/B;AAEA,WAAS,eAAe,IAAY;AAC5B,UAAA,QAAQ,MAAM,MAAM,UAAU,CAAC,SAAS,KAAK,OAAO,EAAE;AAC5D,QAAI,UAAU,IAAI;AACV,YAAA,MAAM,OAAO,OAAO,CAAC;AACTC,8BAAA,EAAE,EAAE,MAAM,MAAM;AAAA,MAAA,CAAc;AAAA,IAClD;AAAA,EACF;AAES,WAAA,eAAe,IAAY,UAAkB;AAC9C,UAAA,OAAO,MAAM,MAAM,KAAK,CAACC,UAASA,MAAK,OAAO,EAAE;AACtD,QAAI,MAAM;AACR,WAAK,WAAW;AAChBC,eAAAA,eAAkB,IAAI,EAAE,SAAA,CAAU,EAAE,MAAM,MAAM;AAAA,MAAA,CAAc;AAAA,IAChE;AAAA,EACF;AAGA,WAAS,YAAY,IAAY;AACzB,UAAA,OAAO,MAAM,MAAM,KAAK,CAACD,UAASA,MAAK,OAAO,EAAE;AACtD,QAAI,MAAM;AACH,WAAA,UAAU,CAAC,KAAK;AAAA,IACvB;AAAA,EACF;AAGA,WAAS,iBAAiB;AACxB,UAAM,aAAa,MAAM,MAAM,MAAM,CAAC,SAAS,KAAK,OAAO;AACrD,UAAA,MAAM,QAAQ,CAAC,SAAS;AAC5B,WAAK,UAAU,CAAC;AAAA,IAAA,CACjB;AAAA,EACH;AAEO,SAAA;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEJ,CAAC;;"}
\ No newline at end of file
diff --git a/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/utils/request.js.map b/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/utils/request.js.map
index 8d697591..7490c6d3 100644
--- a/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/utils/request.js.map
+++ b/miniprogram/unpackage/dist/dev/.sourcemap/mp-weixin/utils/request.js.map
@@ -1 +1 @@
-{"version":3,"file":"request.js","sources":["utils/request.ts"],"sourcesContent":["// 后端 API 基础地址 - 根据环境自动切换\r\n// 开发环境使用本地服务器,生产环境使用线上地址\r\nconst ENV_BASE_URL: Record = {\r\n development: 'http://localhost:3000',\r\n production: 'https://api.example.com', // 部署时替换为真实域名\r\n}\r\n\r\nconst BASE_URL = ENV_BASE_URL[process.env.NODE_ENV || 'development'] || 'http://localhost:3000'\r\n\r\ninterface RequestOptions {\r\n url: string\r\n method?: 'GET' | 'POST' | 'PUT' | 'DELETE'\r\n data?: Record\r\n header?: Record\r\n}\r\n\r\ninterface ApiResponse {\r\n code: number\r\n data: T\r\n message: string\r\n}\r\n\r\nfunction getToken(): string {\r\n return uni.getStorageSync('token') || ''\r\n}\r\n\r\nexport function request(options: RequestOptions): Promise {\r\n const { url, method = 'GET', data, header = {} } = options\r\n const token = getToken()\r\n\r\n return new Promise((resolve, reject) => {\r\n uni.request({\r\n url: `${BASE_URL}${url}`,\r\n method,\r\n data,\r\n header: {\r\n 'Content-Type': 'application/json',\r\n ...(token ? { Authorization: `Bearer ${token}` } : {}),\r\n ...header,\r\n },\r\n success(res) {\r\n const statusCode = res.statusCode\r\n if (statusCode === 401) {\r\n uni.removeStorageSync('token')\r\n uni.showToast({ title: '请重新登录', icon: 'none' })\r\n autoLogin()\r\n reject(new Error('未授权'))\r\n return\r\n }\r\n if (statusCode >= 200 && statusCode < 300) {\r\n const body = res.data as ApiResponse\r\n if (body.code === 0) {\r\n resolve(body.data)\r\n } else {\r\n uni.showToast({ title: body.message || '请求失败', icon: 'none' })\r\n reject(new Error(body.message))\r\n }\r\n } else {\r\n uni.showToast({ title: '网络异常,请稍后重试', icon: 'none' })\r\n reject(new Error(`HTTP ${statusCode}`))\r\n }\r\n },\r\n fail(err) {\r\n uni.showToast({ title: '网络异常,请稍后重试', icon: 'none' })\r\n reject(err)\r\n },\r\n })\r\n })\r\n}\r\n\r\n/** 微信小程序自动登录 */\r\nexport function autoLogin(): Promise {\r\n return new Promise((resolve, reject) => {\r\n uni.login({\r\n provider: 'weixin',\r\n success: async (loginRes) => {\r\n if (loginRes.code) {\r\n try {\r\n const data = await request<{ token: string; userId: number }>({\r\n url: '/api/auth/wx-login',\r\n method: 'POST',\r\n data: { code: loginRes.code },\r\n })\r\n uni.setStorageSync('token', data.token)\r\n resolve()\r\n } catch (err) {\r\n console.error('登录接口调用失败:', err)\r\n reject(err)\r\n }\r\n } else {\r\n console.error('微信登录获取 code 失败')\r\n reject(new Error('获取微信 code 失败'))\r\n }\r\n },\r\n fail: (err) => {\r\n console.error('uni.login 失败:', err)\r\n reject(err)\r\n },\r\n })\r\n })\r\n}\r\n\r\nexport const get = (url: string, data?: Record) =>\r\n request({ url, method: 'GET', data })\r\n\r\nexport const post = (url: string, data?: Record) =>\r\n request({ url, method: 'POST', data })\r\n\r\nexport const put = (url: string, data?: Record) =>\r\n request({ url, method: 'PUT', data })\r\n\r\nexport const del = (url: string, data?: Record) =>\r\n request({ url, method: 'DELETE', data })\r\n"],"names":["uni"],"mappings":";;AAEA,MAAM,eAAuC;AAAA,EAC3C,aAAa;AAAA,EACb,YAAY;AAAA;AACd;AAEA,MAAM,WAAW,aAAa,aAAqC;AAenE,SAAS,WAAmB;AACnB,SAAAA,oBAAI,eAAe,OAAO,KAAK;AACxC;AAEO,SAAS,QAAqB,SAAqC;AAClE,QAAA,EAAE,KAAK,SAAS,OAAO,MAAM,SAAS,CAAA,EAAO,IAAA;AACnD,QAAM,QAAQ;AAEd,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtCA,kBAAAA,MAAI,QAAQ;AAAA,MACV,KAAK,GAAG,QAAQ,GAAG,GAAG;AAAA,MACtB;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,QACN,gBAAgB;AAAA,QAChB,GAAI,QAAQ,EAAE,eAAe,UAAU,KAAK,GAAA,IAAO,CAAC;AAAA,QACpD,GAAG;AAAA,MACL;AAAA,MACA,QAAQ,KAAK;AACX,cAAM,aAAa,IAAI;AACvB,YAAI,eAAe,KAAK;AACtBA,8BAAI,kBAAkB,OAAO;AAC7BA,wBAAA,MAAI,UAAU,EAAE,OAAO,SAAS,MAAM,QAAQ;AACpC;AACH,iBAAA,IAAI,MAAM,KAAK,CAAC;AACvB;AAAA,QACF;AACI,YAAA,cAAc,OAAO,aAAa,KAAK;AACzC,gBAAM,OAAO,IAAI;AACb,cAAA,KAAK,SAAS,GAAG;AACnB,oBAAQ,KAAK,IAAI;AAAA,UAAA,OACZ;AACDA,gCAAA,UAAU,EAAE,OAAO,KAAK,WAAW,QAAQ,MAAM,QAAQ;AAC7D,mBAAO,IAAI,MAAM,KAAK,OAAO,CAAC;AAAA,UAChC;AAAA,QAAA,OACK;AACLA,wBAAA,MAAI,UAAU,EAAE,OAAO,cAAc,MAAM,QAAQ;AACnD,iBAAO,IAAI,MAAM,QAAQ,UAAU,EAAE,CAAC;AAAA,QACxC;AAAA,MACF;AAAA,MACA,KAAK,KAAK;AACRA,sBAAA,MAAI,UAAU,EAAE,OAAO,cAAc,MAAM,QAAQ;AACnD,eAAO,GAAG;AAAA,MACZ;AAAA,IAAA,CACD;AAAA,EAAA,CACF;AACH;AAGO,SAAS,YAA2B;AACzC,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtCA,kBAAAA,MAAI,MAAM;AAAA,MACR,UAAU;AAAA,MACV,SAAS,OAAO,aAAa;AAC3B,YAAI,SAAS,MAAM;AACb,cAAA;AACI,kBAAA,OAAO,MAAM,QAA2C;AAAA,cAC5D,KAAK;AAAA,cACL,QAAQ;AAAA,cACR,MAAM,EAAE,MAAM,SAAS,KAAK;AAAA,YAAA,CAC7B;AACGA,0BAAAA,MAAA,eAAe,SAAS,KAAK,KAAK;AAC9B;mBACD,KAAK;AACZA,0BAAA,MAAA,MAAA,SAAA,0BAAc,aAAa,GAAG;AAC9B,mBAAO,GAAG;AAAA,UACZ;AAAA,QAAA,OACK;AACSA,wBAAAA,MAAA,MAAA,SAAA,0BAAA,gBAAgB;AACvB,iBAAA,IAAI,MAAM,cAAc,CAAC;AAAA,QAClC;AAAA,MACF;AAAA,MACA,MAAM,CAAC,QAAQ;AACbA,sBAAA,MAAA,MAAA,SAAA,0BAAc,iBAAiB,GAAG;AAClC,eAAO,GAAG;AAAA,MACZ;AAAA,IAAA,CACD;AAAA,EAAA,CACF;AACH;AAEa,MAAA,MAAM,CAAc,KAAa,SAC5C,QAAW,EAAE,KAAK,QAAQ,OAAO,MAAM;AAE5B,MAAA,OAAO,CAAc,KAAa,SAC7C,QAAW,EAAE,KAAK,QAAQ,QAAQ,MAAM;AAE7B,MAAA,MAAM,CAAc,KAAa,SAC5C,QAAW,EAAE,KAAK,QAAQ,OAAO,MAAM;AAE5B,MAAA,MAAM,CAAc,KAAa,SAC5C,QAAW,EAAE,KAAK,QAAQ,UAAU,KAAM,CAAA;;;;;;"}
\ No newline at end of file
+{"version":3,"file":"request.js","sources":["utils/request.ts"],"sourcesContent":["// 后端 API 基础地址 - 根据环境自动切换\r\n// 开发环境使用本地服务器,生产环境使用线上地址\r\nconst ENV_BASE_URL: Record = {\r\n development: 'http://localhost:3000',\r\n production: 'https://api.example.com', // 部署时替换为真实域名\r\n}\r\n\r\nconst BASE_URL = ENV_BASE_URL[process.env.NODE_ENV || 'development'] || 'http://localhost:3000'\r\n\r\nexport { BASE_URL }\r\n\r\ninterface RequestOptions {\r\n url: string\r\n method?: 'GET' | 'POST' | 'PUT' | 'DELETE'\r\n data?: Record\r\n header?: Record\r\n}\r\n\r\ninterface ApiResponse {\r\n code: number\r\n data: T\r\n message: string\r\n}\r\n\r\nfunction getToken(): string {\r\n return uni.getStorageSync('token') || ''\r\n}\r\n\r\nexport function request(options: RequestOptions): Promise {\r\n const { url, method = 'GET', data, header = {} } = options\r\n const token = getToken()\r\n\r\n return new Promise((resolve, reject) => {\r\n uni.request({\r\n url: `${BASE_URL}${url}`,\r\n method,\r\n data,\r\n header: {\r\n 'Content-Type': 'application/json',\r\n ...(token ? { Authorization: `Bearer ${token}` } : {}),\r\n ...header,\r\n },\r\n success(res) {\r\n const statusCode = res.statusCode\r\n if (statusCode === 401) {\r\n uni.removeStorageSync('token')\r\n uni.showToast({ title: '请重新登录', icon: 'none' })\r\n autoLogin()\r\n reject(new Error('未授权'))\r\n return\r\n }\r\n if (statusCode >= 200 && statusCode < 300) {\r\n const body = res.data as ApiResponse\r\n if (body.code === 0) {\r\n resolve(body.data)\r\n } else {\r\n uni.showToast({ title: body.message || '请求失败', icon: 'none' })\r\n reject(new Error(body.message))\r\n }\r\n } else {\r\n uni.showToast({ title: '网络异常,请稍后重试', icon: 'none' })\r\n reject(new Error(`HTTP ${statusCode}`))\r\n }\r\n },\r\n fail(err) {\r\n uni.showToast({ title: '网络异常,请稍后重试', icon: 'none' })\r\n reject(err)\r\n },\r\n })\r\n })\r\n}\r\n\r\n/** 微信小程序自动登录 */\r\nexport function autoLogin(): Promise {\r\n return new Promise((resolve, reject) => {\r\n uni.login({\r\n provider: 'weixin',\r\n success: async (loginRes) => {\r\n if (loginRes.code) {\r\n try {\r\n const data = await request<{ token: string; userId: number }>({\r\n url: '/api/auth/wx-login',\r\n method: 'POST',\r\n data: { code: loginRes.code },\r\n })\r\n uni.setStorageSync('token', data.token)\r\n resolve()\r\n } catch (err) {\r\n console.error('登录接口调用失败:', err)\r\n reject(err)\r\n }\r\n } else {\r\n console.error('微信登录获取 code 失败')\r\n reject(new Error('获取微信 code 失败'))\r\n }\r\n },\r\n fail: (err) => {\r\n console.error('uni.login 失败:', err)\r\n reject(err)\r\n },\r\n })\r\n })\r\n}\r\n\r\nexport const get = (url: string, data?: Record) =>\r\n request({ url, method: 'GET', data })\r\n\r\nexport const post = (url: string, data?: Record) =>\r\n request({ url, method: 'POST', data })\r\n\r\nexport const put = (url: string, data?: Record) =>\r\n request({ url, method: 'PUT', data })\r\n\r\nexport const del = (url: string, data?: Record) =>\r\n request({ url, method: 'DELETE', data })\r\n"],"names":["uni"],"mappings":";;AAEA,MAAM,eAAuC;AAAA,EAC3C,aAAa;AAAA,EACb,YAAY;AAAA;AACd;AAEM,MAAA,WAAW,aAAa,aAAqC;AAiBnE,SAAS,WAAmB;AACnB,SAAAA,oBAAI,eAAe,OAAO,KAAK;AACxC;AAEO,SAAS,QAAqB,SAAqC;AAClE,QAAA,EAAE,KAAK,SAAS,OAAO,MAAM,SAAS,CAAA,EAAO,IAAA;AACnD,QAAM,QAAQ;AAEd,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtCA,kBAAAA,MAAI,QAAQ;AAAA,MACV,KAAK,GAAG,QAAQ,GAAG,GAAG;AAAA,MACtB;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,QACN,gBAAgB;AAAA,QAChB,GAAI,QAAQ,EAAE,eAAe,UAAU,KAAK,GAAA,IAAO,CAAC;AAAA,QACpD,GAAG;AAAA,MACL;AAAA,MACA,QAAQ,KAAK;AACX,cAAM,aAAa,IAAI;AACvB,YAAI,eAAe,KAAK;AACtBA,8BAAI,kBAAkB,OAAO;AAC7BA,wBAAA,MAAI,UAAU,EAAE,OAAO,SAAS,MAAM,QAAQ;AACpC;AACH,iBAAA,IAAI,MAAM,KAAK,CAAC;AACvB;AAAA,QACF;AACI,YAAA,cAAc,OAAO,aAAa,KAAK;AACzC,gBAAM,OAAO,IAAI;AACb,cAAA,KAAK,SAAS,GAAG;AACnB,oBAAQ,KAAK,IAAI;AAAA,UAAA,OACZ;AACDA,gCAAA,UAAU,EAAE,OAAO,KAAK,WAAW,QAAQ,MAAM,QAAQ;AAC7D,mBAAO,IAAI,MAAM,KAAK,OAAO,CAAC;AAAA,UAChC;AAAA,QAAA,OACK;AACLA,wBAAA,MAAI,UAAU,EAAE,OAAO,cAAc,MAAM,QAAQ;AACnD,iBAAO,IAAI,MAAM,QAAQ,UAAU,EAAE,CAAC;AAAA,QACxC;AAAA,MACF;AAAA,MACA,KAAK,KAAK;AACRA,sBAAA,MAAI,UAAU,EAAE,OAAO,cAAc,MAAM,QAAQ;AACnD,eAAO,GAAG;AAAA,MACZ;AAAA,IAAA,CACD;AAAA,EAAA,CACF;AACH;AAGO,SAAS,YAA2B;AACzC,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtCA,kBAAAA,MAAI,MAAM;AAAA,MACR,UAAU;AAAA,MACV,SAAS,OAAO,aAAa;AAC3B,YAAI,SAAS,MAAM;AACb,cAAA;AACI,kBAAA,OAAO,MAAM,QAA2C;AAAA,cAC5D,KAAK;AAAA,cACL,QAAQ;AAAA,cACR,MAAM,EAAE,MAAM,SAAS,KAAK;AAAA,YAAA,CAC7B;AACGA,0BAAAA,MAAA,eAAe,SAAS,KAAK,KAAK;AAC9B;mBACD,KAAK;AACZA,0BAAA,MAAA,MAAA,SAAA,0BAAc,aAAa,GAAG;AAC9B,mBAAO,GAAG;AAAA,UACZ;AAAA,QAAA,OACK;AACSA,wBAAAA,MAAA,MAAA,SAAA,0BAAA,gBAAgB;AACvB,iBAAA,IAAI,MAAM,cAAc,CAAC;AAAA,QAClC;AAAA,MACF;AAAA,MACA,MAAM,CAAC,QAAQ;AACbA,sBAAA,MAAA,MAAA,SAAA,0BAAc,iBAAiB,GAAG;AAClC,eAAO,GAAG;AAAA,MACZ;AAAA,IAAA,CACD;AAAA,EAAA,CACF;AACH;AAEa,MAAA,MAAM,CAAc,KAAa,SAC5C,QAAW,EAAE,KAAK,QAAQ,OAAO,MAAM;AAE5B,MAAA,OAAO,CAAc,KAAa,SAC7C,QAAW,EAAE,KAAK,QAAQ,QAAQ,MAAM;AAE7B,MAAA,MAAM,CAAc,KAAa,SAC5C,QAAW,EAAE,KAAK,QAAQ,OAAO,MAAM;AAE5B,MAAA,MAAM,CAAc,KAAa,SAC5C,QAAW,EAAE,KAAK,QAAQ,UAAU,KAAM,CAAA;;;;;;;"}
\ No newline at end of file
diff --git a/miniprogram/unpackage/dist/dev/mp-weixin/api/cart.js b/miniprogram/unpackage/dist/dev/mp-weixin/api/cart.js
index 93a45f30..7f8a1c49 100644
--- a/miniprogram/unpackage/dist/dev/mp-weixin/api/cart.js
+++ b/miniprogram/unpackage/dist/dev/mp-weixin/api/cart.js
@@ -1,5 +1,4 @@
"use strict";
-Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const utils_request = require("../utils/request.js");
const getCartList = () => utils_request.get("/api/cart");
const addToCart = (data) => utils_request.post("/api/cart", data);
diff --git a/miniprogram/unpackage/dist/dev/mp-weixin/common/assets.js b/miniprogram/unpackage/dist/dev/mp-weixin/common/assets.js
index 9f73d75f..6d38d393 100644
--- a/miniprogram/unpackage/dist/dev/mp-weixin/common/assets.js
+++ b/miniprogram/unpackage/dist/dev/mp-weixin/common/assets.js
@@ -1,15 +1,23 @@
"use strict";
-const _imports_0$1 = "/static/tab/me_s.png";
+const _imports_0$4 = "/static/ic_search.png";
+const _imports_0$3 = "/static/ic_back.png";
+const _imports_2$1 = "/static/ic_customer.png";
+const _imports_2 = "/static/tab/car.png";
+const _imports_0$2 = "/static/tab/me_s.png";
const _imports_1 = "/static/ic_address.png";
-const _imports_2 = "/static/ic_customer.png";
const _imports_3 = "/static/ic_about.png";
const _imports_4 = "/static/ic_agreement1.png";
const _imports_5 = "/static/ic_agreement2.png";
-const _imports_0 = "/static/logo.png";
-exports._imports_0 = _imports_0$1;
-exports._imports_0$1 = _imports_0;
+const _imports_0$1 = "/static/logo.png";
+const _imports_0 = "/static/ic_notice.png";
+exports._imports_0 = _imports_0$4;
+exports._imports_0$1 = _imports_0$3;
+exports._imports_0$2 = _imports_0$2;
+exports._imports_0$3 = _imports_0$1;
+exports._imports_0$4 = _imports_0;
exports._imports_1 = _imports_1;
-exports._imports_2 = _imports_2;
+exports._imports_2 = _imports_2$1;
+exports._imports_2$1 = _imports_2;
exports._imports_3 = _imports_3;
exports._imports_4 = _imports_4;
exports._imports_5 = _imports_5;
diff --git a/miniprogram/unpackage/dist/dev/mp-weixin/common/vendor.js b/miniprogram/unpackage/dist/dev/mp-weixin/common/vendor.js
index 0cc6420b..144e015a 100644
--- a/miniprogram/unpackage/dist/dev/mp-weixin/common/vendor.js
+++ b/miniprogram/unpackage/dist/dev/mp-weixin/common/vendor.js
@@ -7041,7 +7041,7 @@ function isConsoleWritable() {
function initRuntimeSocketService() {
const hosts = "172.31.144.1,192.168.21.7,192.168.195.32,127.0.0.1";
const port = "8090";
- const id = "mp-weixin_ucp1tM";
+ const id = "mp-weixin_9p8dl1";
const lazy = typeof swan !== "undefined";
let restoreError = lazy ? () => {
} : initOnError();
diff --git a/miniprogram/unpackage/dist/dev/mp-weixin/components/BannerSwiper.js b/miniprogram/unpackage/dist/dev/mp-weixin/components/BannerSwiper.js
index bb605e83..f1457493 100644
--- a/miniprogram/unpackage/dist/dev/mp-weixin/components/BannerSwiper.js
+++ b/miniprogram/unpackage/dist/dev/mp-weixin/components/BannerSwiper.js
@@ -1,5 +1,6 @@
"use strict";
const common_vendor = require("../common/vendor.js");
+const utils_request = require("../utils/request.js");
const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({
__name: "BannerSwiper",
props: {
@@ -7,15 +8,22 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({
video: {}
},
setup(__props) {
+ function fullUrl(path) {
+ if (!path)
+ return "";
+ if (path.startsWith("http"))
+ return path;
+ return utils_request.BASE_URL + path;
+ }
return (_ctx, _cache) => {
return common_vendor.e({
a: _ctx.video
}, _ctx.video ? {
- b: _ctx.video
+ b: fullUrl(_ctx.video)
} : {}, {
c: common_vendor.f(_ctx.images, (img, idx, i0) => {
return {
- a: img,
+ a: fullUrl(img),
b: idx
};
})
diff --git a/miniprogram/unpackage/dist/dev/mp-weixin/components/BannerSwiper.wxss b/miniprogram/unpackage/dist/dev/mp-weixin/components/BannerSwiper.wxss
index a9862b89..a75bd013 100644
--- a/miniprogram/unpackage/dist/dev/mp-weixin/components/BannerSwiper.wxss
+++ b/miniprogram/unpackage/dist/dev/mp-weixin/components/BannerSwiper.wxss
@@ -1,13 +1,7 @@
-.banner-swiper.data-v-0577c1c5 {
- width: 100%;
- height: 600rpx;
+.banner-swiper.data-v-0577c1c5 { width: 100%; height: 600rpx;
}
-.banner-swiper__image.data-v-0577c1c5 {
- width: 100%;
- height: 600rpx;
+.banner-swiper__image.data-v-0577c1c5 { width: 100%; height: 600rpx;
}
-.banner-swiper__video.data-v-0577c1c5 {
- width: 100%;
- height: 600rpx;
+.banner-swiper__video.data-v-0577c1c5 { width: 100%; height: 600rpx;
}
diff --git a/miniprogram/unpackage/dist/dev/mp-weixin/components/CustomerServiceBtn.js b/miniprogram/unpackage/dist/dev/mp-weixin/components/CustomerServiceBtn.js
index f9c5f314..ef249f88 100644
--- a/miniprogram/unpackage/dist/dev/mp-weixin/components/CustomerServiceBtn.js
+++ b/miniprogram/unpackage/dist/dev/mp-weixin/components/CustomerServiceBtn.js
@@ -12,7 +12,7 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({
return common_vendor.e({
a: _ctx.mode === "qrcode"
}, _ctx.mode === "qrcode" ? {
- b: common_assets._imports_0$1,
+ b: common_assets._imports_0$3,
c: common_vendor.o(($event) => _ctx.$emit("close")),
d: common_vendor.o(() => {
}),
diff --git a/miniprogram/unpackage/dist/dev/mp-weixin/components/ProductCard.js b/miniprogram/unpackage/dist/dev/mp-weixin/components/ProductCard.js
index 39bc5a28..26c5cc9f 100644
--- a/miniprogram/unpackage/dist/dev/mp-weixin/components/ProductCard.js
+++ b/miniprogram/unpackage/dist/dev/mp-weixin/components/ProductCard.js
@@ -1,5 +1,6 @@
"use strict";
const common_vendor = require("../common/vendor.js");
+const utils_request = require("../utils/request.js");
const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({
__name: "ProductCard",
props: {
@@ -7,12 +8,21 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({
},
setup(__props) {
const props = __props;
+ function imgSrc() {
+ var _a;
+ const url = props.product.thumb || ((_a = props.product.bannerImages) == null ? void 0 : _a[0]);
+ if (!url)
+ return "/static/logo.png";
+ if (url.startsWith("http"))
+ return url;
+ return utils_request.BASE_URL + url;
+ }
function goDetail() {
common_vendor.index.navigateTo({ url: `/pages/product/detail?id=${props.product.id}` });
}
return (_ctx, _cache) => {
return {
- a: _ctx.product.bannerImages[0] || "/static/logo.png",
+ a: imgSrc(),
b: common_vendor.t(_ctx.product.name),
c: common_vendor.t(_ctx.product.styleNo),
d: common_vendor.t(_ctx.product.basePrice),
diff --git a/miniprogram/unpackage/dist/dev/mp-weixin/components/ProductCard.wxml b/miniprogram/unpackage/dist/dev/mp-weixin/components/ProductCard.wxml
index bfd72eb6..0367db18 100644
--- a/miniprogram/unpackage/dist/dev/mp-weixin/components/ProductCard.wxml
+++ b/miniprogram/unpackage/dist/dev/mp-weixin/components/ProductCard.wxml
@@ -1 +1 @@
-{{b}}款号:{{c}}¥{{d}}库存 {{e}}
\ No newline at end of file
+{{b}}({{c}})¥{{d}}库存{{e}}
\ No newline at end of file
diff --git a/miniprogram/unpackage/dist/dev/mp-weixin/components/ProductCard.wxss b/miniprogram/unpackage/dist/dev/mp-weixin/components/ProductCard.wxss
index 8e8e84ef..49e66db5 100644
--- a/miniprogram/unpackage/dist/dev/mp-weixin/components/ProductCard.wxss
+++ b/miniprogram/unpackage/dist/dev/mp-weixin/components/ProductCard.wxss
@@ -1,45 +1,45 @@
.product-card.data-v-fe52aa40 {
- display: flex;
- flex-direction: column;
- background: #fff;
- border-radius: 12rpx;
- overflow: hidden;
- width: 100%;
+ display: flex;
+ flex-direction: column;
+ background: #fff;
+ border-radius: 16rpx;
+ overflow: hidden;
+ width: 100%;
}
.product-card__image.data-v-fe52aa40 {
- width: 100%;
- height: 340rpx;
+ width: 100%;
+ height: 340rpx;
}
.product-card__info.data-v-fe52aa40 {
- padding: 16rpx;
+ padding: 16rpx 20rpx 20rpx;
}
.product-card__name.data-v-fe52aa40 {
- font-size: 28rpx;
- color: #333;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- display: block;
-}
-.product-card__style.data-v-fe52aa40 {
- font-size: 22rpx;
- color: #999;
- margin-top: 8rpx;
- display: block;
+ font-size: 26rpx;
+ color: #333;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ display: block;
+ line-height: 1.5;
}
.product-card__bottom.data-v-fe52aa40 {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-top: 12rpx;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-top: 12rpx;
+}
+.product-card__price-tag.data-v-fe52aa40 {
+ background: linear-gradient(135deg, #f5a0b8, #FF6D9B);
+ border-radius: 8rpx;
+ padding: 4rpx 16rpx;
}
.product-card__price.data-v-fe52aa40 {
- font-size: 32rpx;
- color: #e4393c;
- font-weight: bold;
+ font-size: 28rpx;
+ color: #fff;
+ font-weight: bold;
}
.product-card__stock.data-v-fe52aa40 {
- font-size: 22rpx;
- color: #999;
+ font-size: 22rpx;
+ color: #999;
}
diff --git a/miniprogram/unpackage/dist/dev/mp-weixin/components/ShippingNotice.js b/miniprogram/unpackage/dist/dev/mp-weixin/components/ShippingNotice.js
index 1ec82674..da8c4cc8 100644
--- a/miniprogram/unpackage/dist/dev/mp-weixin/components/ShippingNotice.js
+++ b/miniprogram/unpackage/dist/dev/mp-weixin/components/ShippingNotice.js
@@ -1,8 +1,11 @@
"use strict";
+const common_assets = require("../common/assets.js");
const common_vendor = require("../common/vendor.js");
const _sfc_main = {};
function _sfc_render(_ctx, _cache) {
- return {};
+ return {
+ a: common_assets._imports_0$4
+ };
}
const Component = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-807004e7"]]);
wx.createComponent(Component);
diff --git a/miniprogram/unpackage/dist/dev/mp-weixin/components/ShippingNotice.wxml b/miniprogram/unpackage/dist/dev/mp-weixin/components/ShippingNotice.wxml
index a4795147..b279d012 100644
--- a/miniprogram/unpackage/dist/dev/mp-weixin/components/ShippingNotice.wxml
+++ b/miniprogram/unpackage/dist/dev/mp-weixin/components/ShippingNotice.wxml
@@ -1 +1 @@
-发货公告交易方式:线下支付,微信沟通确认客服微信:请点击「联系客服」获取公司地址:请联系客服获取详细地址
\ No newline at end of file
+叶生珠宝-空托之城空托都是当天金工石结算客服微信:15920028399交易方式:加微信门店交易,支付宝,微信,银行卡转账公司地址:深圳市罗湖区水贝二路贝丽花园21栋108叶生珠宝
\ No newline at end of file
diff --git a/miniprogram/unpackage/dist/dev/mp-weixin/components/ShippingNotice.wxss b/miniprogram/unpackage/dist/dev/mp-weixin/components/ShippingNotice.wxss
index c6876ab3..97dd7580 100644
--- a/miniprogram/unpackage/dist/dev/mp-weixin/components/ShippingNotice.wxss
+++ b/miniprogram/unpackage/dist/dev/mp-weixin/components/ShippingNotice.wxss
@@ -1,18 +1,32 @@
.shipping-notice.data-v-807004e7 {
- background: #fffbe6;
- border-radius: 12rpx;
- padding: 20rpx 24rpx;
- margin: 20rpx 24rpx;
+ background: #fce4ec;
+ border-radius: 20rpx;
+ padding: 28rpx 30rpx;
+ margin: 20rpx 24rpx 0;
+}
+.shipping-notice__header.data-v-807004e7 {
+ display: flex;
+ align-items: center;
+ margin-bottom: 20rpx;
+}
+.shipping-notice__icon.data-v-807004e7 {
+ width: 36rpx;
+ height: 36rpx;
+ margin-right: 10rpx;
}
.shipping-notice__title.data-v-807004e7 {
font-size: 28rpx;
- font-weight: bold;
- color: #fa8c16;
- margin-bottom: 12rpx;
+ font-weight: 600;
+ color: #e91e63;
+}
+.shipping-notice__body.data-v-807004e7 {
+ display: flex;
+ flex-direction: column;
+ gap: 8rpx;
}
.shipping-notice__item.data-v-807004e7 {
- font-size: 24rpx;
- color: #666;
- line-height: 40rpx;
+ font-size: 26rpx;
+ color: #e91e63;
+ line-height: 1.6;
}
diff --git a/miniprogram/unpackage/dist/dev/mp-weixin/components/SpecPanel.js b/miniprogram/unpackage/dist/dev/mp-weixin/components/SpecPanel.js
index c37aaa4f..790b4527 100644
--- a/miniprogram/unpackage/dist/dev/mp-weixin/components/SpecPanel.js
+++ b/miniprogram/unpackage/dist/dev/mp-weixin/components/SpecPanel.js
@@ -1,26 +1,58 @@
"use strict";
const common_vendor = require("../common/vendor.js");
const api_product = require("../api/product.js");
+const store_cart = require("../store/cart.js");
const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({
__name: "SpecPanel",
props: {
productId: {}
},
emits: ["close"],
- setup(__props) {
+ setup(__props, { emit: __emit }) {
const props = __props;
+ const emit = __emit;
const config = common_vendor.ref(null);
const loadingConfig = common_vendor.ref(false);
const loadingData = common_vendor.ref(false);
const specDataList = common_vendor.ref([]);
- const selected = common_vendor.reactive({
- fineness: "",
- mainStone: "",
- ringSize: ""
- });
- const canQuery = common_vendor.computed(
- () => selected.fineness && selected.mainStone && selected.ringSize
- );
+ const selectedSpecs = common_vendor.ref(/* @__PURE__ */ new Map());
+ const cartStore = store_cart.useCartStore();
+ const selected = common_vendor.reactive({ fineness: "", mainStone: "", ringSize: "" });
+ function selectOption(key, item) {
+ selected[key] = selected[key] === item ? "" : item;
+ if (selected.fineness || selected.mainStone || selected.ringSize) {
+ querySpecData();
+ } else {
+ specDataList.value = [];
+ }
+ }
+ function toggleSelect(spec) {
+ if (selectedSpecs.value.has(spec.id)) {
+ selectedSpecs.value.delete(spec.id);
+ } else {
+ selectedSpecs.value.set(spec.id, spec);
+ }
+ selectedSpecs.value = new Map(selectedSpecs.value);
+ }
+ function handleAddToCart() {
+ if (selectedSpecs.value.size === 0)
+ return;
+ selectedSpecs.value.forEach((spec) => {
+ cartStore.addToCart({
+ id: Date.now() + spec.id,
+ userId: 0,
+ productId: props.productId,
+ specDataId: spec.id,
+ quantity: 1,
+ product: {},
+ specData: spec,
+ checked: true
+ });
+ });
+ common_vendor.index.showToast({ title: `已加入${selectedSpecs.value.size}件`, icon: "success" });
+ selectedSpecs.value = /* @__PURE__ */ new Map();
+ emit("close");
+ }
common_vendor.onMounted(async () => {
loadingConfig.value = true;
try {
@@ -31,14 +63,12 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({
}
});
async function querySpecData() {
- if (!canQuery.value)
- return;
loadingData.value = true;
try {
specDataList.value = await api_product.getSpecDataList(props.productId, {
- fineness: selected.fineness,
- mainStone: selected.mainStone,
- ringSize: selected.ringSize
+ fineness: selected.fineness || void 0,
+ mainStone: selected.mainStone || void 0,
+ ringSize: selected.ringSize || void 0
});
} catch {
} finally {
@@ -47,63 +77,88 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({
}
return (_ctx, _cache) => {
return common_vendor.e({
- a: common_vendor.o(($event) => _ctx.$emit("close")),
- b: loadingConfig.value
+ a: loadingConfig.value
}, loadingConfig.value ? {} : config.value ? common_vendor.e({
- d: config.value.fineness.length
+ c: config.value.fineness.length
}, config.value.fineness.length ? {
- e: common_vendor.f(config.value.fineness, (item, k0, i0) => {
+ d: common_vendor.f(config.value.fineness, (item, k0, i0) => {
return {
a: common_vendor.t(item),
b: item,
c: selected.fineness === item ? 1 : "",
- d: common_vendor.o(($event) => selected.fineness = item, item)
+ d: common_vendor.o(($event) => selectOption("fineness", item), item)
};
})
} : {}, {
- f: config.value.mainStone.length
+ e: config.value.mainStone.length
}, config.value.mainStone.length ? {
- g: common_vendor.f(config.value.mainStone, (item, k0, i0) => {
+ f: common_vendor.f(config.value.mainStone, (item, k0, i0) => {
return {
a: common_vendor.t(item),
b: item,
c: selected.mainStone === item ? 1 : "",
- d: common_vendor.o(($event) => selected.mainStone = item, item)
+ d: common_vendor.o(($event) => selectOption("mainStone", item), item)
};
})
} : {}, {
- h: config.value.ringSize.length
+ g: config.value.ringSize.length
}, config.value.ringSize.length ? {
- i: common_vendor.f(config.value.ringSize, (item, k0, i0) => {
+ h: common_vendor.f(config.value.ringSize, (item, k0, i0) => {
return {
a: common_vendor.t(item),
b: item,
c: selected.ringSize === item ? 1 : "",
- d: common_vendor.o(($event) => selected.ringSize = item, item)
+ d: common_vendor.o(($event) => selectOption("ringSize", item), item)
};
})
- } : {}, {
- j: !canQuery.value ? 1 : "",
- k: common_vendor.o(querySpecData),
- l: loadingData.value
+ } : {}) : {}, {
+ b: config.value,
+ i: loadingData.value
}, loadingData.value ? {} : specDataList.value.length ? {
- n: common_vendor.f(specDataList.value, (spec, k0, i0) => {
+ k: common_vendor.f(specDataList.value, (spec, k0, i0) => {
return {
a: common_vendor.t(spec.modelName),
- b: common_vendor.t(spec.goldTotalWeight),
- c: common_vendor.t(spec.goldValue),
- d: common_vendor.t(spec.mainStoneAmount),
- e: common_vendor.t(spec.sideStoneAmount),
- f: common_vendor.t(spec.totalLaborCost),
- g: common_vendor.t(spec.totalPrice),
- h: spec.id
+ b: common_vendor.t(spec.fineness),
+ c: common_vendor.t(spec.goldPrice),
+ d: common_vendor.t(spec.modelName),
+ e: common_vendor.t(spec.goldTotalWeight),
+ f: common_vendor.t(spec.goldNetWeight),
+ g: common_vendor.t(spec.goldLoss),
+ h: common_vendor.t(spec.goldValue),
+ i: common_vendor.t(spec.mainStoneCount),
+ j: common_vendor.t(spec.mainStoneWeight),
+ k: common_vendor.t(spec.mainStoneUnitPrice),
+ l: common_vendor.t(spec.mainStoneAmount),
+ m: common_vendor.t(spec.accessoryAmount),
+ n: common_vendor.t(spec.totalLaborCost),
+ o: common_vendor.t(spec.fineness),
+ p: common_vendor.t(spec.loss),
+ q: common_vendor.t(spec.mainStone),
+ r: common_vendor.t(spec.ringSize),
+ s: common_vendor.t(spec.goldPrice),
+ t: common_vendor.t(spec.sideStoneCount),
+ v: common_vendor.t(spec.sideStoneWeight),
+ w: common_vendor.t(spec.sideStoneUnitPrice),
+ x: common_vendor.t(spec.sideStoneAmount),
+ y: common_vendor.t(spec.processingFee),
+ z: common_vendor.t(spec.settingFee),
+ A: common_vendor.t(spec.totalPrice),
+ B: spec.id,
+ C: selectedSpecs.value.has(spec.id) ? 1 : "",
+ D: common_vendor.o(($event) => toggleSelect(spec), spec.id)
};
})
} : {}, {
- m: specDataList.value.length
- }) : {}, {
- c: config.value,
- o: common_vendor.o(($event) => _ctx.$emit("close"))
+ j: specDataList.value.length,
+ l: selectedSpecs.value.size
+ }, selectedSpecs.value.size ? {
+ m: common_vendor.t(selectedSpecs.value.size)
+ } : {}, {
+ n: selectedSpecs.value.size === 0 ? 1 : "",
+ o: common_vendor.o(handleAddToCart),
+ p: common_vendor.o(() => {
+ }),
+ q: common_vendor.o(($event) => _ctx.$emit("close"))
});
};
}
diff --git a/miniprogram/unpackage/dist/dev/mp-weixin/components/SpecPanel.wxml b/miniprogram/unpackage/dist/dev/mp-weixin/components/SpecPanel.wxml
index 3b89617d..b5e800dd 100644
--- a/miniprogram/unpackage/dist/dev/mp-weixin/components/SpecPanel.wxml
+++ b/miniprogram/unpackage/dist/dev/mp-weixin/components/SpecPanel.wxml
@@ -1 +1 @@
-加载中...成色{{item.a}}主石{{item.a}}手寸{{item.a}} 查询规格数据 查询中...型号{{spec.a}}金料总重{{spec.b}}g金值¥{{spec.c}}主石金额¥{{spec.d}}副石金额¥{{spec.e}}总工费¥{{spec.f}}总价¥{{spec.g}}
\ No newline at end of file
+加载中...成 色{{item.a}}主 石{{item.a}}手 寸{{item.a}}查询中...型号名称{{spec.d}}金料总重{{spec.e}}g金料净重{{spec.f}}g金耗{{spec.g}}g金值¥{{spec.h}}主石数量{{spec.i}}粒主石石重{{spec.j}}ct主石单价¥{{spec.k}}主石金额¥{{spec.l}}配件金额¥{{spec.m}}总工费¥{{spec.n}}成色{{spec.o}}损耗{{spec.p}}%主石{{spec.q}}手寸{{spec.r}}金价¥{{spec.s}}副石数量{{spec.t}}粒副石石重{{spec.v}}ct副石单价¥{{spec.w}}副石金额¥{{spec.x}}加工工费¥{{spec.y}}镶石工费¥{{spec.z}} 加入购物车({{m}})
\ No newline at end of file
diff --git a/miniprogram/unpackage/dist/dev/mp-weixin/components/SpecPanel.wxss b/miniprogram/unpackage/dist/dev/mp-weixin/components/SpecPanel.wxss
index 295d5dfb..c4ed24b1 100644
--- a/miniprogram/unpackage/dist/dev/mp-weixin/components/SpecPanel.wxss
+++ b/miniprogram/unpackage/dist/dev/mp-weixin/components/SpecPanel.wxss
@@ -1,114 +1,86 @@
.spec-panel-mask.data-v-c30573e9 {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background: rgba(0, 0, 0, 0.5);
- z-index: 999;
- display: flex;
- align-items: flex-end;
+ position: fixed; top: 0; left: 0; right: 0; bottom: 0;
+ background: rgba(0,0,0,0.5); z-index: 999;
+ display: flex; align-items: flex-end;
}
.spec-panel.data-v-c30573e9 {
- background: #fff;
- width: 100%;
- max-height: 80vh;
+ background: #fff; width: 100%; height: 85vh;
border-radius: 24rpx 24rpx 0 0;
- padding: 32rpx 24rpx;
- overflow-y: auto;
+ display: flex; flex-direction: column;
}
-.spec-panel__header.data-v-c30573e9 {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 24rpx;
-}
-.spec-panel__title.data-v-c30573e9 {
- font-size: 32rpx;
- font-weight: bold;
- color: #333;
-}
-.spec-panel__close.data-v-c30573e9 {
- font-size: 36rpx;
- color: #999;
- padding: 8rpx;
+.spec-panel__scroll.data-v-c30573e9 {
+ flex: 1; padding: 32rpx 28rpx 0; overflow: hidden;
}
.spec-panel__loading.data-v-c30573e9 {
- text-align: center;
- padding: 40rpx 0;
- color: #999;
- font-size: 28rpx;
+ text-align: center; padding: 60rpx 0; color: #999; font-size: 28rpx;
}
-.spec-group.data-v-c30573e9 {
- margin-bottom: 24rpx;
+
+/* 规格分组 */
+.spec-group.data-v-c30573e9 { margin-bottom: 32rpx;
}
.spec-group__label.data-v-c30573e9 {
- font-size: 28rpx;
- color: #333;
- margin-bottom: 16rpx;
- display: block;
+ font-size: 30rpx; color: #333; font-weight: 600;
+ margin-bottom: 20rpx; display: block; letter-spacing: 8rpx;
}
-.spec-group__options.data-v-c30573e9 {
- display: flex;
- flex-wrap: wrap;
- gap: 16rpx;
+.spec-group__options.data-v-c30573e9 { display: flex; flex-wrap: wrap; gap: 16rpx;
}
.spec-option.data-v-c30573e9 {
- padding: 12rpx 28rpx;
- font-size: 26rpx;
- color: #666;
- background: #f5f5f5;
- border-radius: 8rpx;
- border: 2rpx solid transparent;
+ padding: 14rpx 32rpx; font-size: 26rpx; color: #333;
+ background: #f5f5f5; border-radius: 8rpx; border: 2rpx solid #f5f5f5;
}
.spec-option--active.data-v-c30573e9 {
- color: #e4393c;
- background: #fff1f0;
- border-color: #e4393c;
+ color: #e91e63; background: #fce4ec; border-color: #e91e63;
}
-.spec-panel__action.data-v-c30573e9 {
- margin: 24rpx 0;
+
+/* 规格数据卡片 */
+.spec-data-list.data-v-c30573e9 { padding-bottom: 20rpx;
}
-.spec-panel__btn.data-v-c30573e9 {
- background: #e4393c;
- color: #fff;
- text-align: center;
- padding: 20rpx 0;
- border-radius: 44rpx;
- font-size: 28rpx;
+.spec-data-card.data-v-c30573e9 {
+ border: 2rpx solid #f0e0e0; border-radius: 16rpx;
+ padding: 24rpx; margin-bottom: 20rpx; background: #fff;
}
-.spec-panel__btn--disabled.data-v-c30573e9 {
- background: #ccc;
+.spec-data-card--selected.data-v-c30573e9 {
+ border-color: #e91e63; background: #fff5f7;
}
-.spec-data-list.data-v-c30573e9 {
- margin-top: 16rpx;
+.spec-card__header.data-v-c30573e9 {
+ display: flex; justify-content: space-between; align-items: center;
+ margin-bottom: 16rpx; padding-bottom: 16rpx; border-bottom: 1rpx solid #f0f0f0;
}
-.spec-data-item.data-v-c30573e9 {
- background: #fafafa;
- border-radius: 12rpx;
- padding: 20rpx;
- margin-bottom: 16rpx;
+.spec-card__title.data-v-c30573e9 { font-size: 26rpx; color: #333; font-weight: 600;
}
-.spec-data-row.data-v-c30573e9 {
- display: flex;
- justify-content: space-between;
- padding: 6rpx 0;
+.spec-card__gold-price.data-v-c30573e9 { font-size: 24rpx; color: #666;
}
-.spec-data-row--total.data-v-c30573e9 {
- border-top: 1rpx solid #eee;
- margin-top: 8rpx;
- padding-top: 12rpx;
+.spec-card__body.data-v-c30573e9 { display: flex; gap: 12rpx;
}
-.spec-data-label.data-v-c30573e9 {
- font-size: 26rpx;
- color: #999;
+.spec-card__col.data-v-c30573e9 { flex: 1;
}
-.spec-data-value.data-v-c30573e9 {
- font-size: 26rpx;
- color: #333;
+.spec-card__row.data-v-c30573e9 { display: flex; justify-content: space-between; padding: 5rpx 0;
}
-.spec-data-value--price.data-v-c30573e9 {
- color: #e4393c;
- font-weight: bold;
+.spec-card__label.data-v-c30573e9 { font-size: 23rpx; color: #999; flex-shrink: 0;
+}
+.spec-card__value.data-v-c30573e9 { font-size: 23rpx; color: #333; text-align: right;
+}
+.spec-card__footer.data-v-c30573e9 {
+ display: flex; justify-content: flex-end; align-items: center;
+ margin-top: 16rpx; padding-top: 16rpx; border-top: 1rpx solid #f0f0f0; gap: 12rpx;
+}
+.spec-card__total-label.data-v-c30573e9 { font-size: 26rpx; color: #e91e63;
+}
+.spec-card__total-price.data-v-c30573e9 { font-size: 32rpx; color: #e91e63; font-weight: bold;
+}
+
+/* 底部操作栏 */
+.spec-panel__bottom.data-v-c30573e9 {
+ padding: 20rpx 28rpx;
+ padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
+ background: #fff; box-shadow: 0 -2rpx 10rpx rgba(0,0,0,0.05);
+}
+.spec-panel__cart-btn.data-v-c30573e9 {
+ background: linear-gradient(to right, #FFB6C8, #FF6D9B);
+ color: #fff; text-align: center; padding: 24rpx 0;
+ border-radius: 44rpx; font-size: 30rpx; font-weight: 500;
+}
+.spec-panel__cart-btn--disabled.data-v-c30573e9 {
+ background: linear-gradient(to right, #ddd, #ccc);
}
diff --git a/miniprogram/unpackage/dist/dev/mp-weixin/pages/index/index.js b/miniprogram/unpackage/dist/dev/mp-weixin/pages/index/index.js
index e64c874b..317198c9 100644
--- a/miniprogram/unpackage/dist/dev/mp-weixin/pages/index/index.js
+++ b/miniprogram/unpackage/dist/dev/mp-weixin/pages/index/index.js
@@ -1,10 +1,13 @@
"use strict";
const common_vendor = require("../../common/vendor.js");
+const common_assets = require("../../common/assets.js");
const api_product = require("../../api/product.js");
+const utils_request = require("../../utils/request.js");
if (!Math) {
- ProductCard();
+ (ProductCard + CustomerServiceBtn)();
}
const ProductCard = () => "../../components/ProductCard.js";
+const CustomerServiceBtn = () => "../../components/CustomerServiceBtn.js";
const pageSize = 20;
const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({
__name: "index",
@@ -13,11 +16,29 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({
const categories = common_vendor.ref([]);
const activeCategoryId = common_vendor.ref(void 0);
const loading = common_vendor.ref(false);
+ const showQrcode = common_vendor.ref(false);
const page = common_vendor.ref(1);
+ const keyword = common_vendor.ref("");
+ const statusBarHeight = common_vendor.ref(20);
+ const navBarHeight = common_vendor.ref(44);
+ try {
+ const sysInfo = common_vendor.index.getSystemInfoSync();
+ statusBarHeight.value = sysInfo.statusBarHeight || 20;
+ const menuBtn = common_vendor.index.getMenuButtonBoundingClientRect();
+ navBarHeight.value = (menuBtn.top - (sysInfo.statusBarHeight || 20)) * 2 + menuBtn.height;
+ } catch {
+ }
+ function fullUrl(path) {
+ if (!path)
+ return "";
+ if (path.startsWith("http"))
+ return path;
+ return utils_request.BASE_URL + path;
+ }
async function loadCategories() {
try {
const data = await api_product.getCategories();
- categories.value = [{ id: 0, name: "全部", sort: 0 }, ...data];
+ categories.value = data;
} catch {
}
}
@@ -29,9 +50,10 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({
loading.value = true;
try {
const params = { page: page.value, pageSize };
- if (activeCategoryId.value && activeCategoryId.value !== 0) {
+ if (activeCategoryId.value)
params.categoryId = activeCategoryId.value;
- }
+ if (keyword.value)
+ params.keyword = keyword.value;
const data = await api_product.getProducts(params);
if (reset) {
products.value = data.list;
@@ -44,24 +66,40 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({
}
}
function selectCategory(id) {
- activeCategoryId.value = id;
+ activeCategoryId.value = activeCategoryId.value === id ? void 0 : id;
loadProducts(true);
}
+ function goSearch() {
+ }
+ function goCalculator() {
+ common_vendor.index.navigateTo({ url: "/pages/calculator/index" });
+ }
common_vendor.onMounted(() => {
loadCategories();
loadProducts(true);
});
return (_ctx, _cache) => {
return common_vendor.e({
- a: common_vendor.f(categories.value, (cat, k0, i0) => {
- return {
- a: common_vendor.t(cat.name),
- b: cat.id,
- c: activeCategoryId.value === cat.id ? 1 : "",
- d: common_vendor.o(($event) => selectCategory(cat.id), cat.id)
- };
+ a: navBarHeight.value + "px",
+ b: statusBarHeight.value + "px",
+ c: common_assets._imports_0,
+ d: common_vendor.o(goSearch),
+ e: common_vendor.o(goSearch),
+ f: common_vendor.f(categories.value, (cat, k0, i0) => {
+ return common_vendor.e({
+ a: cat.icon
+ }, cat.icon ? {
+ b: fullUrl(cat.icon)
+ } : {}, {
+ c: common_vendor.t(cat.name),
+ d: cat.id,
+ e: activeCategoryId.value === cat.id ? 1 : "",
+ f: common_vendor.o(($event) => selectCategory(cat.id), cat.id)
+ });
}),
- b: common_vendor.f(products.value, (product, k0, i0) => {
+ g: common_vendor.o(goCalculator),
+ h: common_vendor.o(($event) => showQrcode.value = true),
+ i: common_vendor.f(products.value, (product, k0, i0) => {
return {
a: "1cf27b2a-0-" + i0,
b: common_vendor.p({
@@ -70,10 +108,17 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({
c: product.id
};
}),
- c: !loading.value && products.value.length === 0
+ j: !loading.value && products.value.length === 0
}, !loading.value && products.value.length === 0 ? {} : {}, {
- d: loading.value
- }, loading.value ? {} : {});
+ k: loading.value
+ }, loading.value ? {} : {}, {
+ l: showQrcode.value
+ }, showQrcode.value ? {
+ m: common_vendor.o(($event) => showQrcode.value = false),
+ n: common_vendor.p({
+ mode: "qrcode"
+ })
+ } : {});
};
}
});
diff --git a/miniprogram/unpackage/dist/dev/mp-weixin/pages/index/index.json b/miniprogram/unpackage/dist/dev/mp-weixin/pages/index/index.json
index 0cbfe084..0fc044b6 100644
--- a/miniprogram/unpackage/dist/dev/mp-weixin/pages/index/index.json
+++ b/miniprogram/unpackage/dist/dev/mp-weixin/pages/index/index.json
@@ -1,6 +1,7 @@
{
- "navigationBarTitleText": "珠宝商城",
+ "navigationStyle": "custom",
"usingComponents": {
- "product-card": "../../components/ProductCard"
+ "product-card": "../../components/ProductCard",
+ "customer-service-btn": "../../components/CustomerServiceBtn"
}
}
\ No newline at end of file
diff --git a/miniprogram/unpackage/dist/dev/mp-weixin/pages/index/index.wxml b/miniprogram/unpackage/dist/dev/mp-weixin/pages/index/index.wxml
index a42970ef..07263d5c 100644
--- a/miniprogram/unpackage/dist/dev/mp-weixin/pages/index/index.wxml
+++ b/miniprogram/unpackage/dist/dev/mp-weixin/pages/index/index.wxml
@@ -1 +1 @@
-{{cat.a}}暂无商品加载中...
\ No newline at end of file
+凯缘钻之城请输入产品名称、款号、条码号或款式搜索💎{{cat.c}}💎钻戒计算器👩💼客服找款暂无商品加载中...
\ No newline at end of file
diff --git a/miniprogram/unpackage/dist/dev/mp-weixin/pages/index/index.wxss b/miniprogram/unpackage/dist/dev/mp-weixin/pages/index/index.wxss
index 71ee67b8..f065554e 100644
--- a/miniprogram/unpackage/dist/dev/mp-weixin/pages/index/index.wxss
+++ b/miniprogram/unpackage/dist/dev/mp-weixin/pages/index/index.wxss
@@ -1,39 +1,149 @@
.home-page.data-v-1cf27b2a {
- min-height: 100vh;
- background: #f5f5f5;
+ min-height: 100vh;
+ background: #f5f5f5;
}
-.category-bar.data-v-1cf27b2a {
- white-space: nowrap;
- background: #fff;
- padding: 20rpx 16rpx;
+
+ /* 自定义导航栏 */
+.custom-navbar.data-v-1cf27b2a {
+ background: linear-gradient(to right, #FFCFDE, #FFA6C4);
}
-.category-item.data-v-1cf27b2a {
- display: inline-block;
- padding: 12rpx 28rpx;
- margin-right: 16rpx;
- font-size: 26rpx;
- color: #666;
- background: #f5f5f5;
- border-radius: 28rpx;
+.custom-navbar__content.data-v-1cf27b2a {
+ display: flex;
+ align-items: center;
+ justify-content: center;
}
-.category-item--active.data-v-1cf27b2a {
- color: #fff;
- background: #e4393c;
+.custom-navbar__title.data-v-1cf27b2a {
+ font-size: 34rpx;
+ font-weight: bold;
+ color: #333;
}
+
+ /* 搜索栏 */
+.search-bar.data-v-1cf27b2a {
+ display: flex;
+ align-items: center;
+ padding: 16rpx 24rpx;
+}
+.search-bar__input.data-v-1cf27b2a {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ background: #fff;
+ border-radius: 40rpx;
+ padding: 16rpx 24rpx;
+ height: 72rpx;
+ box-sizing: border-box;
+}
+.search-bar__icon.data-v-1cf27b2a {
+ width: 32rpx;
+ height: 32rpx;
+ margin-right: 12rpx;
+}
+.search-bar__placeholder.data-v-1cf27b2a {
+ font-size: 24rpx;
+ color: #999;
+}
+.search-bar__btn.data-v-1cf27b2a {
+ margin-left: 16rpx;
+ font-size: 28rpx;
+ color: #333;
+ font-weight: 500;
+}
+
+ /* 分类图标 */
+.category-section.data-v-1cf27b2a {
+ white-space: nowrap;
+ padding: 32rpx 0 24rpx;
+ background: #FFFFFF;
+}
+.category-section__inner.data-v-1cf27b2a {
+ display: inline-flex;
+ padding: 0 24rpx;
+ gap: 32rpx;
+}
+.category-icon.data-v-1cf27b2a {
+ display: inline-flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 12rpx;
+ flex-shrink: 0;
+}
+.category-icon__circle.data-v-1cf27b2a {
+ width: 120rpx;
+ height: 120rpx;
+ border-radius: 30rpx;
+ background: linear-gradient(135deg, #fce4ec, #f8bbd0);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+.category-icon--active .category-icon__circle.data-v-1cf27b2a {
+ background: linear-gradient(135deg, #f48fb1, #e91e63);
+ box-shadow: 0 4rpx 16rpx rgba(233, 30, 99, 0.3);
+}
+.category-icon__emoji.data-v-1cf27b2a {
+ font-size: 48rpx;
+}
+.category-icon__img.data-v-1cf27b2a {
+ width: 90rpx;
+ height: 90rpx;
+}
+.category-icon__label.data-v-1cf27b2a {
+ font-size: 24rpx;
+ color: #333;
+}
+.category-icon--active .category-icon__label.data-v-1cf27b2a {
+ color: #e91e63;
+ font-weight: bold;
+}
+
+ /* 快捷入口 */
+.quick-actions.data-v-1cf27b2a {
+ display: flex;
+ gap: 20rpx;
+ padding: 0 24rpx 24rpx;
+ background-color: #FFFFFF;
+}
+.quick-action.data-v-1cf27b2a {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 16rpx;
+ padding: 28rpx 0;
+ border-radius: 16rpx;
+ background: #fff;
+}
+.quick-action--calc.data-v-1cf27b2a {
+ background: linear-gradient(135deg, #FFA4C3, #FFD2E0);
+}
+.quick-action--service.data-v-1cf27b2a {
+ background: linear-gradient(135deg, #e8f5e9, #fff);
+}
+.quick-action__icon.data-v-1cf27b2a {
+ font-size: 44rpx;
+}
+.quick-action__text.data-v-1cf27b2a {
+ font-size: 30rpx;
+ color: #333;
+ font-weight: 600;
+}
+
+ /* 商品列表 */
.product-grid.data-v-1cf27b2a {
- display: flex;
- flex-wrap: wrap;
- padding: 16rpx;
- gap: 16rpx;
+ display: flex;
+ flex-wrap: wrap;
+ padding: 0 24rpx;
+ gap: 16rpx;
}
.product-grid__item.data-v-1cf27b2a {
- width: calc(50% - 8rpx);
+ width: calc(50% - 8rpx);
}
.empty-tip.data-v-1cf27b2a,
-.loading-tip.data-v-1cf27b2a {
- text-align: center;
- padding: 60rpx 0;
- color: #999;
- font-size: 28rpx;
+ .loading-tip.data-v-1cf27b2a {
+ text-align: center;
+ padding: 60rpx 0;
+ color: #999;
+ font-size: 28rpx;
}
diff --git a/miniprogram/unpackage/dist/dev/mp-weixin/pages/login/index.js b/miniprogram/unpackage/dist/dev/mp-weixin/pages/login/index.js
index b97d543b..f697ac37 100644
--- a/miniprogram/unpackage/dist/dev/mp-weixin/pages/login/index.js
+++ b/miniprogram/unpackage/dist/dev/mp-weixin/pages/login/index.js
@@ -34,7 +34,7 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({
}
return (_ctx, _cache) => {
return {
- a: common_assets._imports_0$1,
+ a: common_assets._imports_0$3,
b: loading.value,
c: common_vendor.o(handleLogin),
d: common_vendor.o(goBack)
diff --git a/miniprogram/unpackage/dist/dev/mp-weixin/pages/mine/index.js b/miniprogram/unpackage/dist/dev/mp-weixin/pages/mine/index.js
index dcfdf207..6422a6cc 100644
--- a/miniprogram/unpackage/dist/dev/mp-weixin/pages/mine/index.js
+++ b/miniprogram/unpackage/dist/dev/mp-weixin/pages/mine/index.js
@@ -57,7 +57,7 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({
a: ((_a = common_vendor.unref(userStore).user) == null ? void 0 : _a.avatar) || "/static/logo.png",
b: common_vendor.t(isLoggedIn.value ? ((_b = common_vendor.unref(userStore).user) == null ? void 0 : _b.nickname) || "微信用户" : "点击注册/登录"),
c: common_vendor.o(handleUserCardClick),
- d: common_assets._imports_0,
+ d: common_assets._imports_0$2,
e: common_vendor.t(orderCount.value),
f: common_vendor.o(($event) => navigateTo("/pages/order/list")),
g: common_assets._imports_1,
diff --git a/miniprogram/unpackage/dist/dev/mp-weixin/pages/product/detail.js b/miniprogram/unpackage/dist/dev/mp-weixin/pages/product/detail.js
index b8c89ebf..f387d763 100644
--- a/miniprogram/unpackage/dist/dev/mp-weixin/pages/product/detail.js
+++ b/miniprogram/unpackage/dist/dev/mp-weixin/pages/product/detail.js
@@ -1,7 +1,8 @@
"use strict";
const common_vendor = require("../../common/vendor.js");
+const common_assets = require("../../common/assets.js");
const api_product = require("../../api/product.js");
-const store_cart = require("../../store/cart.js");
+const utils_request = require("../../utils/request.js");
if (!Math) {
(BannerSwiper + ShippingNotice + SpecPanel + CustomerServiceBtn)();
}
@@ -15,15 +16,35 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({
const product = common_vendor.ref(null);
const showSpecPanel = common_vendor.ref(false);
const showQrCode = common_vendor.ref(false);
- const cartStore = store_cart.useCartStore();
+ const statusBarHeight = common_vendor.ref(20);
+ const navBarHeight = common_vendor.ref(44);
+ try {
+ const sysInfo = common_vendor.index.getSystemInfoSync();
+ statusBarHeight.value = sysInfo.statusBarHeight || 20;
+ const menuBtn = common_vendor.index.getMenuButtonBoundingClientRect();
+ navBarHeight.value = (menuBtn.top - (sysInfo.statusBarHeight || 20)) * 2 + menuBtn.height;
+ } catch {
+ }
+ function goBack() {
+ common_vendor.index.navigateBack({ delta: 1 });
+ }
+ function fullUrl(path) {
+ if (!path)
+ return "";
+ if (path.startsWith("http"))
+ return path;
+ return utils_request.BASE_URL + path;
+ }
+ function goCart() {
+ common_vendor.index.switchTab({ url: "/pages/cart/index" });
+ }
common_vendor.onMounted(() => {
var _a;
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
const id = Number((_a = currentPage.options) == null ? void 0 : _a.id);
- if (id) {
+ if (id)
loadProduct(id);
- }
});
async function loadProduct(id) {
try {
@@ -32,76 +53,47 @@ const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({
common_vendor.index.showToast({ title: "加载商品失败", icon: "none" });
}
}
- function handleAddToCart() {
- if (!product.value)
- return;
- const item = {
- id: Date.now(),
- userId: 0,
- productId: product.value.id,
- specDataId: 0,
- quantity: 1,
- product: product.value,
- specData: {
- id: 0,
- productId: product.value.id,
- modelName: product.value.name,
- fineness: "",
- mainStone: "",
- ringSize: "",
- goldTotalWeight: 0,
- goldNetWeight: 0,
- loss: 0,
- goldLoss: 0,
- goldPrice: 0,
- goldValue: 0,
- mainStoneCount: 0,
- mainStoneWeight: 0,
- mainStoneUnitPrice: 0,
- mainStoneAmount: 0,
- sideStoneCount: 0,
- sideStoneWeight: 0,
- sideStoneUnitPrice: 0,
- sideStoneAmount: 0,
- accessoryAmount: 0,
- processingFee: 0,
- settingFee: 0,
- totalLaborCost: 0,
- totalPrice: product.value.basePrice
- },
- checked: true
- };
- cartStore.addToCart(item);
- common_vendor.index.showToast({ title: "已加入购物车", icon: "success" });
- }
return (_ctx, _cache) => {
return common_vendor.e({
a: product.value
}, product.value ? common_vendor.e({
- b: common_vendor.p({
- images: product.value.bannerImages,
+ b: common_assets._imports_0$1,
+ c: common_vendor.o(goBack),
+ d: navBarHeight.value + "px",
+ e: statusBarHeight.value + "px",
+ f: statusBarHeight.value + navBarHeight.value + "px",
+ g: common_vendor.p({
+ images: product.value.bannerImages || [],
video: product.value.bannerVideo
}),
- c: common_vendor.t(product.value.basePrice),
- d: common_vendor.t(product.value.name),
- e: common_vendor.t(product.value.styleNo),
- f: common_vendor.t(product.value.stock),
- g: common_vendor.t(product.value.loss),
- h: common_vendor.t(product.value.laborCost),
- i: common_vendor.o(($event) => showSpecPanel.value = true),
- j: showSpecPanel.value
+ h: common_vendor.t(product.value.name),
+ i: common_vendor.t(product.value.basePrice),
+ j: common_vendor.t(product.value.styleNo),
+ k: common_vendor.t(product.value.stock),
+ l: common_vendor.t(product.value.loss),
+ m: common_vendor.t(product.value.laborCost),
+ n: common_vendor.f(product.value.bannerImages || [], (img, idx, i0) => {
+ return {
+ a: idx,
+ b: fullUrl(img)
+ };
+ }),
+ o: common_assets._imports_2,
+ p: common_vendor.o(($event) => showQrCode.value = true),
+ q: common_assets._imports_2$1,
+ r: common_vendor.o(goCart),
+ s: common_vendor.o(($event) => showSpecPanel.value = true),
+ t: showSpecPanel.value
}, showSpecPanel.value ? {
- k: common_vendor.o(($event) => showSpecPanel.value = false),
- l: common_vendor.p({
+ v: common_vendor.o(($event) => showSpecPanel.value = false),
+ w: common_vendor.p({
["product-id"]: product.value.id
})
} : {}, {
- m: common_vendor.o(($event) => showQrCode.value = true),
- n: common_vendor.o(handleAddToCart),
- o: showQrCode.value
+ x: showQrCode.value
}, showQrCode.value ? {
- p: common_vendor.o(($event) => showQrCode.value = false),
- q: common_vendor.p({
+ y: common_vendor.o(($event) => showQrCode.value = false),
+ z: common_vendor.p({
mode: "qrcode"
})
} : {}) : {});
diff --git a/miniprogram/unpackage/dist/dev/mp-weixin/pages/product/detail.json b/miniprogram/unpackage/dist/dev/mp-weixin/pages/product/detail.json
index 6d8d74a5..dec6d7dc 100644
--- a/miniprogram/unpackage/dist/dev/mp-weixin/pages/product/detail.json
+++ b/miniprogram/unpackage/dist/dev/mp-weixin/pages/product/detail.json
@@ -1,5 +1,5 @@
{
- "navigationBarTitleText": "商品详情",
+ "navigationStyle": "custom",
"usingComponents": {
"banner-swiper": "../../components/BannerSwiper",
"shipping-notice": "../../components/ShippingNotice",
diff --git a/miniprogram/unpackage/dist/dev/mp-weixin/pages/product/detail.wxml b/miniprogram/unpackage/dist/dev/mp-weixin/pages/product/detail.wxml
index 94234501..bd1c80a8 100644
--- a/miniprogram/unpackage/dist/dev/mp-weixin/pages/product/detail.wxml
+++ b/miniprogram/unpackage/dist/dev/mp-weixin/pages/product/detail.wxml
@@ -1 +1 @@
-¥{{c}}{{d}}款号{{e}}库存{{f}}损耗{{g}}工费¥{{h}}查看详细参数›客服加入购物车
\ No newline at end of file
+商品详情{{h}}¥{{i}}元款 号{{j}}库存{{k}}损 耗{{l}}%工费¥{{m}}商品详情客服购物车空托—查看详细参数
\ No newline at end of file
diff --git a/miniprogram/unpackage/dist/dev/mp-weixin/pages/product/detail.wxss b/miniprogram/unpackage/dist/dev/mp-weixin/pages/product/detail.wxss
index ba8bd432..5354c428 100644
--- a/miniprogram/unpackage/dist/dev/mp-weixin/pages/product/detail.wxss
+++ b/miniprogram/unpackage/dist/dev/mp-weixin/pages/product/detail.wxss
@@ -1,54 +1,135 @@
.product-detail.data-v-acf502d9 {
- padding-bottom: 120rpx;
+ padding-bottom: 140rpx;
background: #f5f5f5;
}
+
+/* 自定义导航栏 */
+.custom-navbar.data-v-acf502d9 {
+ background: linear-gradient(to right, #FFCFDE, #FFA6C4);
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ z-index: 100;
+}
+.custom-navbar__content.data-v-acf502d9 {
+ display: flex;
+ align-items: center;
+ padding: 0 24rpx;
+}
+.custom-navbar__back.data-v-acf502d9 {
+ width: 44rpx;
+ height: 44rpx;
+}
+.custom-navbar__title.data-v-acf502d9 {
+ flex: 1;
+ text-align: center;
+ font-size: 34rpx;
+ font-weight: bold;
+ color: #333;
+}
+.custom-navbar__placeholder.data-v-acf502d9 {
+ width: 44rpx;
+}
+
+/* Banner 容器 */
+.banner-wrapper.data-v-acf502d9 {
+ margin: 20rpx 24rpx 0;
+ border-radius: 20rpx;
+ overflow: hidden;
+}
+
+/* 基础信息卡片 */
.base-info.data-v-acf502d9 {
background: #fff;
- padding: 24rpx;
+ margin: 20rpx 24rpx 0;
+ border-radius: 20rpx;
+ padding: 30rpx;
}
-.base-info__price.data-v-acf502d9 {
- font-size: 40rpx;
- color: #e4393c;
- font-weight: bold;
- display: block;
+.base-info__top.data-v-acf502d9 {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
}
.base-info__name.data-v-acf502d9 {
font-size: 32rpx;
color: #333;
- margin-top: 12rpx;
- display: block;
+ font-weight: 600;
+ flex: 1;
+ margin-right: 20rpx;
}
+.base-info__price.data-v-acf502d9 {
+ display: flex;
+ align-items: baseline;
+ color: #FF6D9B;
+ flex-shrink: 0;
+}
+.base-info__price-symbol.data-v-acf502d9 {
+ font-size: 30rpx;
+ font-weight: bold;
+}
+.base-info__price-num.data-v-acf502d9 {
+ font-size: 48rpx;
+ font-weight: bold;
+}
+.base-info__price-unit.data-v-acf502d9 {
+ font-size: 24rpx;
+ margin-left: 4rpx;
+}
+
+/* 属性行 - 两列布局 */
.base-info__attrs.data-v-acf502d9 {
margin-top: 20rpx;
+ border-top: 1rpx solid #f0f0f0;
+ padding-top: 20rpx;
}
.attr-row.data-v-acf502d9 {
display: flex;
- justify-content: space-between;
+ align-items: center;
padding: 8rpx 0;
}
.attr-label.data-v-acf502d9 {
font-size: 26rpx;
color: #999;
+ width: 80rpx;
+ flex-shrink: 0;
+ letter-spacing: 4rpx;
}
.attr-value.data-v-acf502d9 {
- font-size: 26rpx;
- color: #333;
-}
-.spec-entry.data-v-acf502d9 {
- display: flex;
- justify-content: space-between;
- align-items: center;
- background: #fff;
- margin-top: 16rpx;
- padding: 24rpx;
font-size: 28rpx;
color: #333;
+ min-width: 180rpx;
+ margin-right: 40rpx;
}
-.spec-entry__arrow.data-v-acf502d9 {
- color: #999;
- font-size: 32rpx;
+
+/* 商品详情大图 */
+.detail-section.data-v-acf502d9 {
+ background: #fff;
+ margin: 20rpx 24rpx 0;
+ border-radius: 20rpx;
+ padding: 30rpx;
}
+.detail-section__title.data-v-acf502d9 {
+ text-align: center;
+ font-size: 30rpx;
+ color: #333;
+ font-weight: 600;
+ padding-bottom: 24rpx;
+ border-bottom: 1rpx solid #eee;
+ margin-bottom: 24rpx;
+}
+.detail-section__images.data-v-acf502d9 {
+ display: flex;
+ flex-direction: column;
+ gap: 8rpx;
+}
+.detail-section__img.data-v-acf502d9 {
+ width: 100%;
+ border-radius: 12rpx;
+}
+
+/* 底部操作栏 */
.bottom-bar.data-v-acf502d9 {
position: fixed;
bottom: 0;
@@ -56,24 +137,38 @@
right: 0;
background: #fff;
padding: 16rpx 24rpx;
+ padding-bottom: calc(16rpx + env(safe-area-inset-bottom));
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.05);
display: flex;
- gap: 16rpx;
+ align-items: center;
+ gap: 20rpx;
}
-.bottom-bar__btn.data-v-acf502d9 {
+.bottom-bar__icons.data-v-acf502d9 {
+ display: flex;
+ gap: 32rpx;
+ flex-shrink: 0;
+}
+.bottom-bar__icon-item.data-v-acf502d9 {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 4rpx;
+}
+.bottom-bar__icon-img.data-v-acf502d9 {
+ width: 44rpx;
+ height: 44rpx;
+}
+.bottom-bar__icon-text.data-v-acf502d9 {
+ font-size: 20rpx;
+ color: #666;
+}
+.bottom-bar__main-btn.data-v-acf502d9 {
+ flex: 1;
+ background: linear-gradient(to right, #f5a0b8, #e4393c);
+ color: #fff;
text-align: center;
- padding: 20rpx 0;
+ padding: 24rpx 0;
border-radius: 44rpx;
font-size: 30rpx;
-}
-.bottom-bar__btn--cs.data-v-acf502d9 {
- flex: 1;
- border: 1rpx solid #ddd;
- color: #666;
- background: #fff;
-}
-.bottom-bar__btn--cart.data-v-acf502d9 {
- flex: 2;
- background: #e4393c;
- color: #fff;
+ font-weight: 500;
}
diff --git a/miniprogram/unpackage/dist/dev/mp-weixin/static/ic_back.png b/miniprogram/unpackage/dist/dev/mp-weixin/static/ic_back.png
new file mode 100644
index 00000000..0166203b
Binary files /dev/null and b/miniprogram/unpackage/dist/dev/mp-weixin/static/ic_back.png differ
diff --git a/miniprogram/unpackage/dist/dev/mp-weixin/static/ic_notice.png b/miniprogram/unpackage/dist/dev/mp-weixin/static/ic_notice.png
new file mode 100644
index 00000000..4c940a83
Binary files /dev/null and b/miniprogram/unpackage/dist/dev/mp-weixin/static/ic_notice.png differ
diff --git a/miniprogram/unpackage/dist/dev/mp-weixin/static/ic_search.png b/miniprogram/unpackage/dist/dev/mp-weixin/static/ic_search.png
new file mode 100644
index 00000000..b0c04b82
Binary files /dev/null and b/miniprogram/unpackage/dist/dev/mp-weixin/static/ic_search.png differ
diff --git a/miniprogram/unpackage/dist/dev/mp-weixin/store/cart.js b/miniprogram/unpackage/dist/dev/mp-weixin/store/cart.js
index 19c42d19..3f55963a 100644
--- a/miniprogram/unpackage/dist/dev/mp-weixin/store/cart.js
+++ b/miniprogram/unpackage/dist/dev/mp-weixin/store/cart.js
@@ -1,5 +1,6 @@
"use strict";
const common_vendor = require("../common/vendor.js");
+const api_cart = require("../api/cart.js");
const useCartStore = common_vendor.defineStore("cart", () => {
const items = common_vendor.ref([]);
const checkedItems = common_vendor.computed(() => items.value.filter((item) => item.checked));
@@ -8,21 +9,17 @@ const useCartStore = common_vendor.defineStore("cart", () => {
);
async function fetchCart() {
try {
- const { getCartList } = await "../api/cart.js";
- const list = await getCartList();
+ const list = await api_cart.getCartList();
items.value = list.map((item) => ({ ...item, checked: true }));
} catch {
}
}
function addToCart(item) {
items.value.push(item);
- "../api/cart.js".then(({ addToCart: apiAdd }) => {
- apiAdd({
- productId: item.productId,
- specDataId: item.specDataId,
- quantity: item.quantity
- }).catch(() => {
- });
+ api_cart.addToCart({
+ productId: item.productId,
+ specDataId: item.specDataId,
+ quantity: item.quantity
}).catch(() => {
});
}
@@ -30,10 +27,7 @@ const useCartStore = common_vendor.defineStore("cart", () => {
const index = items.value.findIndex((item) => item.id === id);
if (index !== -1) {
items.value.splice(index, 1);
- "../api/cart.js".then(({ deleteCartItem }) => {
- deleteCartItem(id).catch(() => {
- });
- }).catch(() => {
+ api_cart.deleteCartItem(id).catch(() => {
});
}
}
@@ -41,10 +35,7 @@ const useCartStore = common_vendor.defineStore("cart", () => {
const item = items.value.find((item2) => item2.id === id);
if (item) {
item.quantity = quantity;
- "../api/cart.js".then(({ updateCartItem }) => {
- updateCartItem(id, { quantity }).catch(() => {
- });
- }).catch(() => {
+ api_cart.updateCartItem(id, { quantity }).catch(() => {
});
}
}
diff --git a/miniprogram/unpackage/dist/dev/mp-weixin/utils/request.js b/miniprogram/unpackage/dist/dev/mp-weixin/utils/request.js
index 027c3bfa..da3e16fd 100644
--- a/miniprogram/unpackage/dist/dev/mp-weixin/utils/request.js
+++ b/miniprogram/unpackage/dist/dev/mp-weixin/utils/request.js
@@ -66,16 +66,16 @@ function autoLogin() {
common_vendor.index.setStorageSync("token", data.token);
resolve();
} catch (err) {
- common_vendor.index.__f__("error", "at utils/request.ts:87", "登录接口调用失败:", err);
+ common_vendor.index.__f__("error", "at utils/request.ts:89", "登录接口调用失败:", err);
reject(err);
}
} else {
- common_vendor.index.__f__("error", "at utils/request.ts:91", "微信登录获取 code 失败");
+ common_vendor.index.__f__("error", "at utils/request.ts:93", "微信登录获取 code 失败");
reject(new Error("获取微信 code 失败"));
}
},
fail: (err) => {
- common_vendor.index.__f__("error", "at utils/request.ts:96", "uni.login 失败:", err);
+ common_vendor.index.__f__("error", "at utils/request.ts:98", "uni.login 失败:", err);
reject(err);
}
});
@@ -85,6 +85,7 @@ const get = (url, data) => request({ url, method: "GET", data });
const post = (url, data) => request({ url, method: "POST", data });
const put = (url, data) => request({ url, method: "PUT", data });
const del = (url, data) => request({ url, method: "DELETE", data });
+exports.BASE_URL = BASE_URL;
exports.autoLogin = autoLogin;
exports.del = del;
exports.get = get;
diff --git a/miniprogram/utils/request.ts b/miniprogram/utils/request.ts
index 7fd38cc2..e366f7e7 100644
--- a/miniprogram/utils/request.ts
+++ b/miniprogram/utils/request.ts
@@ -7,6 +7,8 @@ const ENV_BASE_URL: Record = {
const BASE_URL = ENV_BASE_URL[process.env.NODE_ENV || 'development'] || 'http://localhost:3000'
+export { BASE_URL }
+
interface RequestOptions {
url: string
method?: 'GET' | 'POST' | 'PUT' | 'DELETE'
diff --git a/server/migrations/001_init.sql b/server/migrations/001_init.sql
index ea7e6d36..7bacc569 100644
--- a/server/migrations/001_init.sql
+++ b/server/migrations/001_init.sql
@@ -29,6 +29,7 @@ CREATE TABLE IF NOT EXISTS products (
category_id INT DEFAULT NULL,
banner_images JSON DEFAULT NULL,
banner_video VARCHAR(512) DEFAULT NULL,
+ thumb VARCHAR(512) DEFAULT NULL,
status ENUM('on','off') NOT NULL DEFAULT 'on',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
diff --git a/server/src/controllers/adminCategory.ts b/server/src/controllers/adminCategory.ts
new file mode 100644
index 00000000..16b2f2e7
--- /dev/null
+++ b/server/src/controllers/adminCategory.ts
@@ -0,0 +1,55 @@
+import { Request, Response } from 'express'
+import pool from '../utils/db'
+import { RowDataPacket, ResultSetHeader } from 'mysql2'
+
+// GET /api/admin/categories
+export async function adminGetCategories(_req: Request, res: Response): Promise {
+ try {
+ const [rows] = await pool.execute(
+ 'SELECT id, name, icon, parent_id, sort FROM categories ORDER BY sort ASC, id ASC'
+ )
+ res.json({ code: 0, data: rows })
+ } catch (err) {
+ console.error('adminGetCategories error:', err)
+ res.status(500).json({ code: 500, message: '获取分类列表失败' })
+ }
+}
+
+// POST /api/admin/categories
+export async function adminCreateCategory(req: Request, res: Response): Promise {
+ try {
+ const { name, parentId, sort, icon } = req.body
+ if (!name || !name.trim()) {
+ res.status(400).json({ code: 400, message: '分类名称不能为空' })
+ return
+ }
+ const [result] = await pool.execute(
+ 'INSERT INTO categories (name, icon, parent_id, sort) VALUES (?, ?, ?, ?)',
+ [name.trim(), icon || null, parentId || null, sort ?? 0]
+ )
+ res.json({ code: 0, data: { id: result.insertId } })
+ } catch (err) {
+ console.error('adminCreateCategory error:', err)
+ res.status(500).json({ code: 500, message: '创建分类失败' })
+ }
+}
+
+// DELETE /api/admin/categories/:id
+export async function adminDeleteCategory(req: Request, res: Response): Promise {
+ try {
+ const { id } = req.params
+ // Check if any products use this category
+ const [products] = await pool.execute(
+ 'SELECT COUNT(*) as count FROM products WHERE category_id = ?', [id]
+ )
+ if (products[0].count > 0) {
+ res.status(400).json({ code: 400, message: '该分类下有商品,无法删除' })
+ return
+ }
+ await pool.execute('DELETE FROM categories WHERE id = ?', [id])
+ res.json({ code: 0, message: '删除成功' })
+ } catch (err) {
+ console.error('adminDeleteCategory error:', err)
+ res.status(500).json({ code: 500, message: '删除分类失败' })
+ }
+}
diff --git a/server/src/controllers/adminProduct.ts b/server/src/controllers/adminProduct.ts
index 00d52bff..f7dea2fc 100644
--- a/server/src/controllers/adminProduct.ts
+++ b/server/src/controllers/adminProduct.ts
@@ -50,7 +50,7 @@ export async function adminGetProductDetail(req: Request, res: Response): Promis
const { id } = req.params
const [rows] = await pool.execute(
`SELECT id, name, base_price, style_no, stock, total_stock, loss, labor_cost,
- category_id, banner_images, banner_video, status, created_at, updated_at
+ category_id, banner_images, banner_video, thumb, status, created_at, updated_at
FROM products WHERE id = ?`,
[id]
)
@@ -71,7 +71,7 @@ export async function adminGetProductDetail(req: Request, res: Response): Promis
export async function adminCreateProduct(req: Request, res: Response): Promise {
const conn = await pool.getConnection()
try {
- const { name, basePrice, styleNo, stock, totalStock, loss, laborCost, categoryId, bannerImages, bannerVideo, status, detailParams } = req.body
+ const { name, basePrice, styleNo, stock, totalStock, loss, laborCost, categoryId, bannerImages, bannerVideo, thumb, status, detailParams } = req.body
if (!name) {
res.status(400).json({ code: 400, message: '商品名称不能为空' })
@@ -81,9 +81,9 @@ export async function adminCreateProduct(req: Request, res: Response): Promise(
- `INSERT INTO products (name, base_price, style_no, stock, total_stock, loss, labor_cost, category_id, banner_images, banner_video, status)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
- [name, basePrice || 0, styleNo || '', stock || 0, totalStock || 0, loss || 0, laborCost || 0, categoryId || null, JSON.stringify(bannerImages || []), bannerVideo || null, status || 'on']
+ `INSERT INTO products (name, base_price, style_no, stock, total_stock, loss, labor_cost, category_id, banner_images, banner_video, thumb, status)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
+ [name, basePrice || 0, styleNo || '', stock || 0, totalStock || 0, loss || 0, laborCost || 0, categoryId || null, JSON.stringify(bannerImages || []), bannerVideo || null, thumb || null, status || 'on']
)
const productId = result.insertId
@@ -111,14 +111,14 @@ export async function adminUpdateProduct(req: Request, res: Response): Promise {
const total = countRows[0].total
const [rows] = await pool.execute(
- `SELECT id, name, base_price, style_no, stock, banner_images, status
+ `SELECT id, name, base_price AS basePrice, style_no AS styleNo, stock, banner_images AS bannerImages, thumb, status
FROM products ${where}
ORDER BY id DESC LIMIT ? OFFSET ?`,
[...params, String(pageSize), String(offset)]
@@ -43,8 +43,10 @@ export async function getProductDetail(req: Request, res: Response): Promise(
- `SELECT id, name, base_price, style_no, stock, total_stock, loss, labor_cost,
- category_id, banner_images, banner_video, status, created_at, updated_at
+ `SELECT id, name, base_price AS basePrice, style_no AS styleNo, stock, total_stock AS totalStock,
+ loss, labor_cost AS laborCost, category_id AS categoryId,
+ banner_images AS bannerImages, banner_video AS bannerVideo, thumb, status,
+ created_at AS createdAt, updated_at AS updatedAt
FROM products WHERE id = ?`,
[id]
)
@@ -66,7 +68,7 @@ export async function getProductSpecs(req: Request, res: Response): Promise(
- 'SELECT id, product_id, fineness, main_stone, ring_size FROM detail_parameter_configs WHERE product_id = ?',
+ 'SELECT id, product_id AS productId, fineness, main_stone AS mainStone, ring_size AS ringSize FROM detail_parameter_configs WHERE product_id = ?',
[id]
)
@@ -100,7 +102,16 @@ export async function getSpecData(req: Request, res: Response): Promise {
}
const [rows] = await pool.execute(
- `SELECT * FROM spec_data ${where}`,
+ `SELECT id, product_id AS productId, model_name AS modelName, fineness, main_stone AS mainStone,
+ ring_size AS ringSize, gold_total_weight AS goldTotalWeight, gold_net_weight AS goldNetWeight,
+ loss, gold_loss AS goldLoss, gold_price AS goldPrice, gold_value AS goldValue,
+ main_stone_count AS mainStoneCount, main_stone_weight AS mainStoneWeight,
+ main_stone_unit_price AS mainStoneUnitPrice, main_stone_amount AS mainStoneAmount,
+ side_stone_count AS sideStoneCount, side_stone_weight AS sideStoneWeight,
+ side_stone_unit_price AS sideStoneUnitPrice, side_stone_amount AS sideStoneAmount,
+ accessory_amount AS accessoryAmount, processing_fee AS processingFee,
+ setting_fee AS settingFee, total_labor_cost AS totalLaborCost, total_price AS totalPrice
+ FROM spec_data ${where}`,
params
)
@@ -115,7 +126,7 @@ export async function getSpecData(req: Request, res: Response): Promise {
export async function getCategories(_req: Request, res: Response): Promise {
try {
const [rows] = await pool.execute(
- 'SELECT id, name, parent_id, sort FROM categories ORDER BY sort ASC'
+ 'SELECT id, name, icon, parent_id AS parentId, sort FROM categories ORDER BY sort ASC'
)
res.json({ code: 0, data: rows })
} catch (err) {
diff --git a/server/src/controllers/specDataIO.ts b/server/src/controllers/specDataIO.ts
index 1bb0cb3e..3593b509 100644
--- a/server/src/controllers/specDataIO.ts
+++ b/server/src/controllers/specDataIO.ts
@@ -77,6 +77,68 @@ export function generateCSV(rows: Record[]): string {
return [headerLine, ...dataLines].join('\n')
}
+// GET /api/admin/products/:id/spec-data - 获取规格数据列表
+export async function adminGetSpecData(req: Request, res: Response): Promise {
+ try {
+ const { id } = req.params
+ const [rows] = await pool.execute(
+ `SELECT id, product_id AS productId, model_name AS modelName, fineness, main_stone AS mainStone,
+ ring_size AS ringSize, gold_total_weight AS goldTotalWeight, gold_net_weight AS goldNetWeight,
+ loss, gold_loss AS goldLoss, gold_price AS goldPrice, gold_value AS goldValue,
+ main_stone_count AS mainStoneCount, main_stone_weight AS mainStoneWeight,
+ main_stone_unit_price AS mainStoneUnitPrice, main_stone_amount AS mainStoneAmount,
+ side_stone_count AS sideStoneCount, side_stone_weight AS sideStoneWeight,
+ side_stone_unit_price AS sideStoneUnitPrice, side_stone_amount AS sideStoneAmount,
+ accessory_amount AS accessoryAmount, processing_fee AS processingFee,
+ setting_fee AS settingFee, total_labor_cost AS totalLaborCost, total_price AS totalPrice
+ FROM spec_data WHERE product_id = ? ORDER BY id ASC`,
+ [id]
+ )
+ res.json({ code: 0, data: rows })
+ } catch (err) {
+ console.error('adminGetSpecData error:', err)
+ res.status(500).json({ code: 500, message: '获取规格数据失败' })
+ }
+}
+
+// POST /api/admin/products/:id/spec-data - 新增单条规格数据
+export async function adminCreateSpecData(req: Request, res: Response): Promise {
+ try {
+ const { id } = req.params
+ const d = req.body
+ const [result] = await pool.execute(
+ `INSERT INTO spec_data (product_id, model_name, fineness, main_stone, ring_size,
+ gold_total_weight, gold_net_weight, loss, gold_loss, gold_price, gold_value,
+ main_stone_count, main_stone_weight, main_stone_unit_price, main_stone_amount,
+ side_stone_count, side_stone_weight, side_stone_unit_price, side_stone_amount,
+ accessory_amount, processing_fee, setting_fee, total_labor_cost, total_price)
+ VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,
+ [id, d.modelName||'', d.fineness||'', d.mainStone||'', d.ringSize||'',
+ d.goldTotalWeight||0, d.goldNetWeight||0, d.loss||0, d.goldLoss||0,
+ d.goldPrice||0, d.goldValue||0,
+ d.mainStoneCount||0, d.mainStoneWeight||0, d.mainStoneUnitPrice||0, d.mainStoneAmount||0,
+ d.sideStoneCount||0, d.sideStoneWeight||0, d.sideStoneUnitPrice||0, d.sideStoneAmount||0,
+ d.accessoryAmount||0, d.processingFee||0, d.settingFee||0, d.totalLaborCost||0, d.totalPrice||0]
+ )
+ res.json({ code: 0, data: { id: result.insertId } })
+ } catch (err) {
+ console.error('adminCreateSpecData error:', err)
+ res.status(500).json({ code: 500, message: '新增规格数据失败' })
+ }
+}
+
+// DELETE /api/admin/products/:productId/spec-data/:specId
+export async function adminDeleteSpecData(req: Request, res: Response): Promise {
+ try {
+ const { specId } = req.params
+ await pool.execute('DELETE FROM spec_data WHERE id = ?', [specId])
+ res.json({ code: 0, message: '删除成功' })
+ } catch (err) {
+ console.error('adminDeleteSpecData error:', err)
+ res.status(500).json({ code: 500, message: '删除规格数据失败' })
+ }
+}
+
// GET /api/admin/products/:id/spec-data/export
export async function exportSpecData(req: Request, res: Response): Promise {
try {
diff --git a/server/src/routes/admin.ts b/server/src/routes/admin.ts
index fbf25c3c..47dd363c 100644
--- a/server/src/routes/admin.ts
+++ b/server/src/routes/admin.ts
@@ -9,7 +9,7 @@ import {
adminUpdateProduct,
adminDeleteProduct,
} from '../controllers/adminProduct'
-import { exportSpecData, importSpecData } from '../controllers/specDataIO'
+import { exportSpecData, importSpecData, adminGetSpecData, adminCreateSpecData, adminDeleteSpecData } from '../controllers/specDataIO'
import { getStockAlerts } from '../controllers/stockAlert'
import {
adminGetOrders,
@@ -24,6 +24,11 @@ import {
adminUpdateMold,
adminDeleteMold,
} from '../controllers/adminMold'
+import {
+ adminGetCategories,
+ adminCreateCategory,
+ adminDeleteCategory,
+} from '../controllers/adminCategory'
const csvUpload = multer({ storage: multer.memoryStorage() })
@@ -45,9 +50,12 @@ adminRoutes.post('/products', adminCreateProduct)
adminRoutes.put('/products/:id', adminUpdateProduct)
adminRoutes.delete('/products/:id', adminDeleteProduct)
-// Spec data import/export
+// Spec data CRUD + import/export
adminRoutes.get('/products/:id/spec-data/export', exportSpecData)
adminRoutes.post('/products/:id/spec-data/import', csvUpload.single('file'), importSpecData)
+adminRoutes.get('/products/:id/spec-data', adminGetSpecData)
+adminRoutes.post('/products/:id/spec-data', adminCreateSpecData)
+adminRoutes.delete('/products/:productId/spec-data/:specId', adminDeleteSpecData)
// Stock alerts
adminRoutes.get('/stock-alerts', getStockAlerts)
@@ -64,3 +72,8 @@ adminRoutes.get('/molds', adminGetMolds)
adminRoutes.post('/molds', adminCreateMold)
adminRoutes.put('/molds/:id', adminUpdateMold)
adminRoutes.delete('/molds/:id', adminDeleteMold)
+
+// Category management
+adminRoutes.get('/categories', adminGetCategories)
+adminRoutes.post('/categories', adminCreateCategory)
+adminRoutes.delete('/categories/:id', adminDeleteCategory)
diff --git a/server/src/utils/db.ts b/server/src/utils/db.ts
index b478a50f..40e84c6e 100644
--- a/server/src/utils/db.ts
+++ b/server/src/utils/db.ts
@@ -9,6 +9,7 @@ const pool = mysql.createPool({
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0,
+ charset: 'utf8mb4',
})
export default pool