From 5bbca05d2e15651fa0a3cd979df46ac80ac6f8be Mon Sep 17 00:00:00 2001 From: not-like-juvenile <16056107+not-like-juvenile@user.noreply.gitee.com> Date: Tue, 3 Feb 2026 17:30:00 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E9=85=8D=E9=80=81=E7=AB=AF=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=BA=93=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../delivery/db/create_pending_orders.sql | 104 +++++ pages/mall/delivery/db/create_test_orders.sql | 213 +++++++++ .../mall/delivery/db/realistic_mock_data.sql | 408 ++++++++++++++++++ 3 files changed, 725 insertions(+) create mode 100644 pages/mall/delivery/db/create_pending_orders.sql create mode 100644 pages/mall/delivery/db/create_test_orders.sql create mode 100644 pages/mall/delivery/db/realistic_mock_data.sql diff --git a/pages/mall/delivery/db/create_pending_orders.sql b/pages/mall/delivery/db/create_pending_orders.sql new file mode 100644 index 00000000..ff454deb --- /dev/null +++ b/pages/mall/delivery/db/create_pending_orders.sql @@ -0,0 +1,104 @@ +-- create_pending_orders.sql +-- 在 dev 环境幂等创建若干 "待接取" 订单及对应配送任务 +-- 使用说明:在 Supabase SQL Editor 中选择 Role = postgres,整体执行此文件。 + +-- 订单 PENDING-20260202-001 +WITH o AS ( + INSERT INTO public.ml_orders (order_no, user_id, merchant_id, product_amount, shipping_fee, total_amount, shipping_address, order_status, created_at, updated_at) + SELECT 'PENDING-20260202-001', + COALESCE((SELECT id FROM public.ak_users WHERE email='zhang.san@example.com' LIMIT 1),(SELECT id FROM public.ak_users LIMIT 1)), + (SELECT id FROM public.ak_users WHERE email='merchant.real@example.com' LIMIT 1), + 12.50, 3.00, 15.50, + ('{"contact":"张三","phone":"13811112222","detail":"测试地址 A"}')::jsonb, + 1, NOW(), NOW() + WHERE NOT EXISTS (SELECT 1 FROM public.ml_orders WHERE order_no='PENDING-20260202-001') + RETURNING id +), it AS ( + INSERT INTO public.ml_order_items (id, order_id, product_id, product_name, price, quantity, total_amount, created_at) + SELECT uuid_generate_v4(), (SELECT id FROM o), + COALESCE((SELECT id FROM public.ml_products WHERE product_code='REAL-P-A-20260202' LIMIT 1),(SELECT id FROM public.ml_products LIMIT 1)), + COALESCE((SELECT name FROM public.ml_products WHERE product_code='REAL-P-A-20260202' LIMIT 1),'商品A'), + COALESCE((SELECT base_price FROM public.ml_products WHERE product_code='REAL-P-A-20260202' LIMIT 1),12.50),1, + COALESCE((SELECT base_price FROM public.ml_products WHERE product_code='REAL-P-A-20260202' LIMIT 1),12.50), NOW() + WHERE EXISTS (SELECT 1 FROM o) + RETURNING id +), t AS ( + INSERT INTO public.ml_delivery_tasks (order_id, pickup_address, delivery_address, delivery_fee, status, created_at, updated_at) + SELECT (SELECT id FROM o), + ('{"contact":"门店A","phone":"13900000001","detail":"门店A"}')::jsonb, + ('{"contact":"张三","phone":"13811112222","detail":"测试地址 A"}')::jsonb, + 3.00, 1, NOW(), NOW() + WHERE EXISTS (SELECT 1 FROM o) + RETURNING id +) +SELECT 'PENDING-20260202-001' AS order_no, (SELECT id FROM o) AS order_id, (SELECT id FROM t) AS task_id; + +-- 订单 PENDING-20260202-002 +WITH o AS ( + INSERT INTO public.ml_orders (order_no, user_id, merchant_id, product_amount, shipping_fee, total_amount, shipping_address, order_status, created_at, updated_at) + SELECT 'PENDING-20260202-002', + COALESCE((SELECT id FROM public.ak_users WHERE email='li.si@example.com' LIMIT 1),(SELECT id FROM public.ak_users LIMIT 1)), + (SELECT id FROM public.ak_users WHERE email='merchant.real@example.com' LIMIT 1), + 35.00, 4.00, 39.00, + ('{"contact":"李四","phone":"13822223333","detail":"测试地址 B"}')::jsonb, + 1, NOW(), NOW() + WHERE NOT EXISTS (SELECT 1 FROM public.ml_orders WHERE order_no='PENDING-20260202-002') + RETURNING id +), it AS ( + INSERT INTO public.ml_order_items (id, order_id, product_id, product_name, price, quantity, total_amount, created_at) + SELECT uuid_generate_v4(), (SELECT id FROM o), + COALESCE((SELECT id FROM public.ml_products WHERE product_code='REAL-P-B-20260202' LIMIT 1),(SELECT id FROM public.ml_products LIMIT 1)), + COALESCE((SELECT name FROM public.ml_products WHERE product_code='REAL-P-B-20260202' LIMIT 1),'商品B'), + COALESCE((SELECT base_price FROM public.ml_products WHERE product_code='REAL-P-B-20260202' LIMIT 1),35.00),1, + COALESCE((SELECT base_price FROM public.ml_products WHERE product_code='REAL-P-B-20260202' LIMIT 1),35.00), NOW() + WHERE EXISTS (SELECT 1 FROM o) + RETURNING id +), t AS ( + INSERT INTO public.ml_delivery_tasks (order_id, pickup_address, delivery_address, delivery_fee, status, created_at, updated_at) + SELECT (SELECT id FROM o), + ('{"contact":"门店B","phone":"13900000002","detail":"门店B"}')::jsonb, + ('{"contact":"李四","phone":"13822223333","detail":"测试地址 B"}')::jsonb, + 4.00, 1, NOW(), NOW() + WHERE EXISTS (SELECT 1 FROM o) + RETURNING id +) +SELECT 'PENDING-20260202-002' AS order_no, (SELECT id FROM o) AS order_id, (SELECT id FROM t) AS task_id; + +-- 订单 PENDING-20260202-003 +WITH o AS ( + INSERT INTO public.ml_orders (order_no, user_id, merchant_id, product_amount, shipping_fee, total_amount, shipping_address, order_status, created_at, updated_at) + SELECT 'PENDING-20260202-003', + COALESCE((SELECT id FROM public.ak_users WHERE email='wang.wu@example.com' LIMIT 1),(SELECT id FROM public.ak_users LIMIT 1)), + (SELECT id FROM public.ak_users WHERE email='merchant.real@example.com' LIMIT 1), + 22.00, 3.50, 25.50, + ('{"contact":"王五","phone":"13833334444","detail":"测试地址 C"}')::jsonb, + 1, NOW(), NOW() + WHERE NOT EXISTS (SELECT 1 FROM public.ml_orders WHERE order_no='PENDING-20260202-003') + RETURNING id +), it AS ( + INSERT INTO public.ml_order_items (id, order_id, product_id, product_name, price, quantity, total_amount, created_at) + SELECT uuid_generate_v4(), (SELECT id FROM o), + COALESCE((SELECT id FROM public.ml_products WHERE product_code='REAL-P-C-20260202' LIMIT 1),(SELECT id FROM public.ml_products LIMIT 1)), + COALESCE((SELECT name FROM public.ml_products WHERE product_code='REAL-P-C-20260202' LIMIT 1),'商品C'), + COALESCE((SELECT base_price FROM public.ml_products WHERE product_code='REAL-P-C-20260202' LIMIT 1),22.00),1, + COALESCE((SELECT base_price FROM public.ml_products WHERE product_code='REAL-P-C-20260202' LIMIT 1),22.00), NOW() + WHERE EXISTS (SELECT 1 FROM o) + RETURNING id +), t AS ( + INSERT INTO public.ml_delivery_tasks (order_id, pickup_address, delivery_address, delivery_fee, status, created_at, updated_at) + SELECT (SELECT id FROM o), + ('{"contact":"门店C","phone":"13900000003","detail":"门店C"}')::jsonb, + ('{"contact":"王五","phone":"13833334444","detail":"测试地址 C"}')::jsonb, + 3.50, 1, NOW(), NOW() + WHERE EXISTS (SELECT 1 FROM o) + RETURNING id +) +SELECT 'PENDING-20260202-003' AS order_no, (SELECT id FROM o) AS order_id, (SELECT id FROM t) AS task_id; + +-- 最终:列出新建或已存在的 pending 订单 +SELECT order_no, order_id, task_id FROM ( + VALUES + ('PENDING-20260202-001',(SELECT id FROM public.ml_orders WHERE order_no='PENDING-20260202-001' LIMIT 1),(SELECT id FROM public.ml_delivery_tasks dt JOIN public.ml_orders o ON dt.order_id=o.id WHERE o.order_no='PENDING-20260202-001' LIMIT 1)), + ('PENDING-20260202-002',(SELECT id FROM public.ml_orders WHERE order_no='PENDING-20260202-002' LIMIT 1),(SELECT id FROM public.ml_delivery_tasks dt JOIN public.ml_orders o ON dt.order_id=o.id WHERE o.order_no='PENDING-20260202-002' LIMIT 1)), + ('PENDING-20260202-003',(SELECT id FROM public.ml_orders WHERE order_no='PENDING-20260202-003' LIMIT 1),(SELECT id FROM public.ml_delivery_tasks dt JOIN public.ml_orders o ON dt.order_id=o.id WHERE o.order_no='PENDING-20260202-003' LIMIT 1)) +) AS t(order_no, order_id, task_id); diff --git a/pages/mall/delivery/db/create_test_orders.sql b/pages/mall/delivery/db/create_test_orders.sql new file mode 100644 index 00000000..700e9250 --- /dev/null +++ b/pages/mall/delivery/db/create_test_orders.sql @@ -0,0 +1,213 @@ +-- create_test_orders.sql +-- 幂等的测试订单生成脚本: +-- 1) 确保必需的 ak_users, ml_categories, ml_products, ml_product_skus 存在 +-- 2) 插入 3 个订单(含 order_items)并为每个订单创建 ml_delivery_tasks +-- 3) 适用于 complete_mall_database.sql 所建表(在 Supabase SQL Editor 中以 postgres 角色运行) + +BEGIN; + +-- 1. 确保测试用户存在(若不存在则插入简化记录) +-- 使用 WHERE NOT EXISTS 保证幂等 +INSERT INTO public.ak_users(id, auth_id, username, role, email, phone, avatar_url, status, registration_source, created_at, updated_at) +SELECT uuid_generate_v4(), uuid_generate_v4(), '系统管理员', 'admin', 'admin@mall.com', '13800138000', NULL, 'active', 'script', NOW(), NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ak_users WHERE email = 'admin@mall.com'); + +INSERT INTO public.ak_users(id, auth_id, username, role, email, phone, avatar_url, status, registration_source, created_at, updated_at) +SELECT uuid_generate_v4(), uuid_generate_v4(), '数码专营店', 'merchant', 'merchant1@mall.com', '13800138001', NULL, 'active', 'script', NOW(), NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ak_users WHERE email = 'merchant1@mall.com'); + +INSERT INTO public.ak_users(id, auth_id, username, role, email, phone, avatar_url, status, registration_source, created_at, updated_at) +SELECT uuid_generate_v4(), uuid_generate_v4(), '时尚小铺', 'merchant', 'merchant2@mall.com', '13800138002', NULL, 'active', 'script', NOW(), NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ak_users WHERE email = 'merchant2@mall.com'); + +INSERT INTO public.ak_users(id, auth_id, username, role, email, phone, avatar_url, status, registration_source, created_at, updated_at) +SELECT uuid_generate_v4(), uuid_generate_v4(), '张小明', 'customer', 'customer1@mall.com', '13800138101', NULL, 'active', 'script', NOW(), NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ak_users WHERE email = 'customer1@mall.com'); + +INSERT INTO public.ak_users(id, auth_id, username, role, email, phone, avatar_url, status, registration_source, created_at, updated_at) +SELECT uuid_generate_v4(), uuid_generate_v4(), '李小红', 'customer', 'customer2@mall.com', '13800138102', NULL, 'active', 'script', NOW(), NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ak_users WHERE email = 'customer2@mall.com'); + +INSERT INTO public.ak_users(id, auth_id, username, role, email, phone, avatar_url, status, registration_source, created_at, updated_at) +SELECT uuid_generate_v4(), uuid_generate_v4(), '快递小哥1', 'delivery', 'driver1@mall.com', '13800138201', NULL, 'active', 'script', NOW(), NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ak_users WHERE email = 'driver1@mall.com'); + +-- 2. 确保至少有一个分类存在 +INSERT INTO public.ml_categories (id, name, slug, level, path, created_at, updated_at) +SELECT uuid_generate_v4(), '默认分类', 'default', 1, ARRAY['默认分类'], NOW(), NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_categories); + +-- 3. 为每个商家确保至少有一个商品和 SKU +-- 3.1 Helper: 若商家没有商品则插入一个最小商品 +WITH merchant1 AS ( + SELECT id AS merchant_id FROM public.ak_users WHERE email = 'merchant1@mall.com' LIMIT 1 +), merchant2 AS ( + SELECT id AS merchant_id FROM public.ak_users WHERE email = 'merchant2@mall.com' LIMIT 1 +), default_cat AS ( + SELECT id AS category_id FROM public.ml_categories LIMIT 1 +) +-- 插入商品(商家1) +INSERT INTO public.ml_products (id, merchant_id, category_id, product_code, name, base_price, total_stock, available_stock, created_at, updated_at) +SELECT uuid_generate_v4(), m.merchant_id, d.category_id, 'P-M1-001', '示例商品 - 商家1', 199.00, 50, 50, NOW(), NOW() +FROM merchant1 m, default_cat d +WHERE NOT EXISTS ( + SELECT 1 FROM public.ml_products p WHERE p.merchant_id = m.merchant_id LIMIT 1 +); + +-- 插入商品(商家2) +INSERT INTO public.ml_products (id, merchant_id, category_id, product_code, name, base_price, total_stock, available_stock, created_at, updated_at) +SELECT uuid_generate_v4(), + (SELECT id FROM public.ak_users WHERE email = 'merchant2@mall.com' LIMIT 1), + (SELECT id FROM public.ml_categories LIMIT 1), + 'P-M2-001', '示例商品 - 商家2', 89.00, 80, 80, NOW(), NOW() +WHERE NOT EXISTS ( + SELECT 1 FROM public.ml_products p WHERE p.merchant_id = (SELECT id FROM public.ak_users WHERE email = 'merchant2@mall.com') LIMIT 1 +); + +-- 3.2 插入 SKU(如果没有) +WITH p1 AS ( + SELECT id AS product_id FROM public.ml_products WHERE merchant_id = (SELECT id FROM public.ak_users WHERE email = 'merchant1@mall.com') LIMIT 1 +), p2 AS ( + SELECT id AS product_id FROM public.ml_products WHERE merchant_id = (SELECT id FROM public.ak_users WHERE email = 'merchant2@mall.com') LIMIT 1 +) +INSERT INTO public.ml_product_skus (id, product_id, sku_code, price, stock, created_at, updated_at) +SELECT uuid_generate_v4(), p.product_id, 'SKU-M1-001', 199.00, 50, NOW(), NOW() FROM p1 p +WHERE NOT EXISTS (SELECT 1 FROM public.ml_product_skus s WHERE s.product_id = p.product_id LIMIT 1); + +-- 插入商家2 的 SKU(使用内联子查询,确保幂等且避免 CTE 范围问题) +INSERT INTO public.ml_product_skus (id, product_id, sku_code, price, stock, created_at, updated_at) +SELECT uuid_generate_v4(), p.product_id, 'SKU-M2-001', 89.00, 80, NOW(), NOW() +FROM ( + SELECT id AS product_id + FROM public.ml_products + WHERE merchant_id = (SELECT id FROM public.ak_users WHERE email = 'merchant2@mall.com' LIMIT 1) + LIMIT 1 +) p +WHERE p.product_id IS NOT NULL + AND NOT EXISTS (SELECT 1 FROM public.ml_product_skus s WHERE s.product_id = p.product_id LIMIT 1); + +-- 4. 插入 3 个订单:两个不同商家各一单 + 一个多商品订单 +-- 订单 1: customer1 从 merchant1 购买 1 件 +WITH +buyer AS (SELECT id AS user_id FROM public.ak_users WHERE email = 'customer1@mall.com' LIMIT 1), +merchant AS (SELECT id AS merchant_id FROM public.ak_users WHERE email = 'merchant1@mall.com' LIMIT 1), +prod AS (SELECT id AS product_id FROM public.ml_products WHERE merchant_id = (SELECT merchant_id FROM merchant) LIMIT 1), +sku AS (SELECT id AS sku_id, price FROM public.ml_product_skus WHERE product_id = (SELECT product_id FROM prod) LIMIT 1), +ins_order AS ( + INSERT INTO public.ml_orders (id, order_no, user_id, merchant_id, product_amount, discount_amount, shipping_fee, total_amount, paid_amount, shipping_address, order_status, payment_status, shipping_status, created_at, updated_at) + SELECT uuid_generate_v4(), public.generate_order_no(), b.user_id, m.merchant_id, s.price, 0, 10.00, s.price + 10.00, 0, + jsonb_build_object('receiver_name','王小明','receiver_phone','13800138003','province','北京市','city','朝阳区','district','望京街道','address_detail','望京SOHO T1座 1201室'), + 1, 1, 1, NOW(), NOW() + FROM buyer b, merchant m, sku s + RETURNING id +) +INSERT INTO public.ml_order_items (id, order_id, product_id, sku_id, product_name, sku_name, price, quantity, total_amount, created_at) +SELECT uuid_generate_v4(), o.id, p.product_id, s.sku_id, '示例商品 - 商家1', '默认SKU', s.price, 1, s.price * 1, NOW() +FROM ins_order o, prod p, sku s; + +-- 创建配送任务 for 订单1 +INSERT INTO public.ml_delivery_tasks (id, order_id, driver_id, pickup_address, delivery_address, distance, estimated_time, delivery_fee, status, assigned_at, created_at, updated_at) +SELECT uuid_generate_v4(), o.id, (SELECT id FROM public.ml_delivery_drivers WHERE user_id = (SELECT id FROM public.ak_users WHERE email = 'driver1@mall.com') LIMIT 1), + jsonb_build_object('address','商家取货点','phone','010-00000001'), + jsonb_build_object('receiver_name','王小明','receiver_phone','13800138003','address_detail','望京SOHO T1座 1201室'), + 3.5, 20, 5.00, 1, NOW(), NOW(), NOW() +FROM (SELECT id FROM public.ml_orders WHERE id = (SELECT id FROM public.ml_orders ORDER BY created_at DESC LIMIT 1) LIMIT 1) o +WHERE NOT EXISTS (SELECT 1 FROM public.ml_delivery_tasks t WHERE t.order_id = o.id); + +-- 订单 2: customer2 从 merchant2 购买 2 件 +WITH +buyer2 AS (SELECT id AS user_id FROM public.ak_users WHERE email = 'customer2@mall.com' LIMIT 1), +merchantB AS (SELECT id AS merchant_id FROM public.ak_users WHERE email = 'merchant2@mall.com' LIMIT 1), +prodB AS (SELECT id AS product_id FROM public.ml_products WHERE merchant_id = (SELECT merchant_id FROM merchantB) LIMIT 1), +skuB AS (SELECT id AS sku_id, price FROM public.ml_product_skus WHERE product_id = (SELECT product_id FROM prodB) LIMIT 1), +ins_order2 AS ( + INSERT INTO public.ml_orders (id, order_no, user_id, merchant_id, product_amount, discount_amount, shipping_fee, total_amount, paid_amount, shipping_address, order_status, payment_status, shipping_status, created_at, updated_at) + SELECT uuid_generate_v4(), public.generate_order_no(), b.user_id, m.merchant_id, s.price * 2, 0, 8.00, s.price * 2 + 8.00, 0, + jsonb_build_object('receiver_name','李小红','receiver_phone','13800138004','province','北京市','city','海淀区','district','中关村街道','address_detail','中关村大街1号 科技大厦'), + 1, 1, 1, NOW(), NOW() + FROM buyer2 b, merchantB m, skuB s + RETURNING id +) +INSERT INTO public.ml_order_items (id, order_id, product_id, sku_id, product_name, sku_name, price, quantity, total_amount, created_at) +SELECT uuid_generate_v4(), o.id, p.product_id, s.sku_id, '示例商品 - 商家2', '默认SKU', s.price, 2, s.price * 2, NOW() +FROM ins_order2 o, prodB p, skuB s; + +-- 创建配送任务 for 订单2 +INSERT INTO public.ml_delivery_tasks (id, order_id, driver_id, pickup_address, delivery_address, distance, estimated_time, delivery_fee, status, assigned_at, created_at, updated_at) +SELECT uuid_generate_v4(), o.id, (SELECT id FROM public.ml_delivery_drivers WHERE user_id = (SELECT id FROM public.ak_users WHERE email = 'driver1@mall.com') LIMIT 1), + jsonb_build_object('address','商家取货点','phone','010-00000002'), + jsonb_build_object('receiver_name','李小红','receiver_phone','13800138004','address_detail','中关村大街1号 科技大厦'), + 6.0, 35, 6.50, 1, NOW(), NOW(), NOW() +FROM (SELECT id FROM public.ml_orders WHERE created_at = (SELECT MAX(created_at) FROM public.ml_orders) LIMIT 1) o +WHERE NOT EXISTS (SELECT 1 FROM public.ml_delivery_tasks t WHERE t.order_id = o.id); + +-- 订单 3: customer1 购买商家1 的商品 + 商家2 的商品(跨店多商品示例,示意用) +-- 备注:实际业务可能不允许跨商家单一订单,这里仅作为测试多商品记录演示(如果系统不允许,请忽略) +WITH +buyer3 AS (SELECT id AS user_id FROM public.ak_users WHERE email = 'customer1@mall.com' LIMIT 1), +m1 AS (SELECT id AS merchant1_id FROM public.ak_users WHERE email = 'merchant1@mall.com' LIMIT 1), +m2 AS (SELECT id AS merchant2_id FROM public.ak_users WHERE email = 'merchant2@mall.com' LIMIT 1), +prod1 AS (SELECT id AS product1_id FROM public.ml_products WHERE merchant_id = (SELECT merchant1_id FROM m1) LIMIT 1), +sku1 AS (SELECT id AS sku1_id, price FROM public.ml_product_skus WHERE product_id = (SELECT product1_id FROM prod1) LIMIT 1), +prod2 AS (SELECT id AS product2_id FROM public.ml_products WHERE merchant_id = (SELECT merchant2_id FROM m2) LIMIT 1), +sku2 AS (SELECT id AS sku2_id, price FROM public.ml_product_skus WHERE product_id = (SELECT product2_id FROM prod2) LIMIT 1), +ins_order3 AS ( + INSERT INTO public.ml_orders (id, order_no, user_id, merchant_id, product_amount, discount_amount, shipping_fee, total_amount, paid_amount, shipping_address, order_status, payment_status, shipping_status, created_at, updated_at) + SELECT uuid_generate_v4(), public.generate_order_no(), b.user_id, (SELECT merchant1_id FROM m1), + COALESCE(s1.price,0) + COALESCE(s2.price,0), 0, 12.00, COALESCE(s1.price,0)+COALESCE(s2.price,0)+12.00, 0, + jsonb_build_object('receiver_name','王小明','receiver_phone','13800138003','province','北京市','city','朝阳区','district','望京街道','address_detail','望京SOHO T1座 1201室'), + 1,1,1, NOW(), NOW() + FROM buyer3 b LEFT JOIN sku1 s1 ON TRUE LEFT JOIN sku2 s2 ON TRUE + RETURNING id +) +INSERT INTO public.ml_order_items (id, order_id, product_id, sku_id, product_name, sku_name, price, quantity, total_amount, created_at) +SELECT + uuid_generate_v4(), + o.id, + (SELECT id FROM public.ml_products WHERE merchant_id = (SELECT id FROM public.ak_users WHERE email = 'merchant1@mall.com') LIMIT 1) AS product_id, + (SELECT id FROM public.ml_product_skus WHERE product_id = (SELECT id FROM pu SELECT id, email, username, role, auth_id FROM public.ak_users WHERE email = '123@123.com';blic.ml_products WHERE merchant_id = (SELECT id FROM public.ak_users WHERE email = 'merchant1@mall.com') LIMIT 1) LIMIT 1) AS sku_id, + '示例商品 - 商家1', + '默认SKU', + COALESCE((SELECT price FROM public.ml_product_skus WHERE product_id = (SELECT id FROM public.ml_products WHERE merchant_id = (SELECT id FROM public.ak_users WHERE email = 'merchant1@mall.com') LIMIT 1) LIMIT 1),0) AS price, + 1, + COALESCE((SELECT price FROM public.ml_product_skus WHERE product_id = (SELECT id FROM public.ml_products WHERE merchant_id = (SELECT id FROM public.ak_users WHERE email = 'merchant1@mall.com') LIMIT 1) LIMIT 1),0) AS total_amount, + NOW() +FROM ( + SELECT id FROM public.ml_orders WHERE created_at = (SELECT MAX(created_at) FROM public.ml_orders) LIMIT 1 +) o +WHERE (SELECT id FROM public.ml_product_skus WHERE product_id = (SELECT id FROM public.ml_products WHERE merchant_id = (SELECT id FROM public.ak_users WHERE email = 'merchant1@mall.com') LIMIT 1) LIMIT 1) IS NOT NULL +ON CONFLICT DO NOTHING; + +INSERT INTO public.ml_order_items (id, order_id, product_id, sku_id, product_name, sku_name, price, quantity, total_amount, created_at) +SELECT + uuid_generate_v4(), + o.id, + (SELECT id FROM public.ml_products WHERE merchant_id = (SELECT id FROM public.ak_users WHERE email = 'merchant2@mall.com') LIMIT 1) AS product_id, + (SELECT id FROM public.ml_product_skus WHERE product_id = (SELECT id FROM public.ml_products WHERE merchant_id = (SELECT id FROM public.ak_users WHERE email = 'merchant2@mall.com') LIMIT 1) LIMIT 1) AS sku_id, + '示例商品 - 商家2', + '默认SKU', + COALESCE((SELECT price FROM public.ml_product_skus WHERE product_id = (SELECT id FROM public.ml_products WHERE merchant_id = (SELECT id FROM public.ak_users WHERE email = 'merchant2@mall.com') LIMIT 1) LIMIT 1),0) AS price, + 1, + COALESCE((SELECT price FROM public.ml_product_skus WHERE product_id = (SELECT id FROM public.ml_products WHERE merchant_id = (SELECT id FROM public.ak_users WHERE email = 'merchant2@mall.com') LIMIT 1) LIMIT 1),0) AS total_amount, + NOW() +FROM ( + SELECT id FROM public.ml_orders WHERE created_at = (SELECT MAX(created_at) FROM public.ml_orders) LIMIT 1 +) o +WHERE (SELECT id FROM public.ml_product_skus WHERE product_id = (SELECT id FROM public.ml_products WHERE merchant_id = (SELECT id FROM public.ak_users WHERE email = 'merchant2@mall.com') LIMIT 1) LIMIT 1) IS NOT NULL +ON CONFLICT DO NOTHING; + +-- 为订单3 创建配送任务(若存在) +INSERT INTO public.ml_delivery_tasks (id, order_id, driver_id, pickup_address, delivery_address, distance, estimated_time, delivery_fee, status, assigned_at, created_at, updated_at) +SELECT uuid_generate_v4(), o.id, (SELECT id FROM public.ml_delivery_drivers WHERE user_id = (SELECT id FROM public.ak_users WHERE email = 'driver1@mall.com') LIMIT 1), + jsonb_build_object('address','商家取货点','phone','010-00000003'), + jsonb_build_object('receiver_name','王小明','receiver_phone','13800138003','address_detail','望京SOHO T1座 1201室'), + 5.0, 30, 7.00, 1, NOW(), NOW(), NOW() +FROM (SELECT id FROM public.ml_orders WHERE created_at = (SELECT MAX(created_at) FROM public.ml_orders) LIMIT 1) o +WHERE NOT EXISTS (SELECT 1 FROM public.ml_delivery_tasks t WHERE t.order_id = o.id); + +COMMIT; + +-- 执行完成后请在 Supabase SQL Editor 中确认插入结果: +-- SELECT * FROM public.ml_orders ORDER BY created_at DESC LIMIT 10; +-- SELECT * FROM public.ml_order_items ORDER BY created_at DESC LIMIT 20; +-- SELECT * FROM public.ml_delivery_tasks ORDER BY created_at DESC LIMIT 10; diff --git a/pages/mall/delivery/db/realistic_mock_data.sql b/pages/mall/delivery/db/realistic_mock_data.sql new file mode 100644 index 00000000..f4ccae12 --- /dev/null +++ b/pages/mall/delivery/db/realistic_mock_data.sql @@ -0,0 +1,408 @@ +-- realistic_mock_data.sql +-- 幂等脚本:在 dev 环境创建更真实的测试数据 +-- 使用说明:在 Supabase SQL Editor 中选择 Role = postgres,整体执行此文件。 + +-- 运行前确保至少存在一个 auth 用户,否则后续插入会违背 FK +DO $$ +BEGIN + IF NOT EXISTS (SELECT 1 FROM auth.users) THEN + RAISE EXCEPTION 'No auth.users found. Create at least one auth user in Supabase auth or sign up once, then re-run this script.'; + END IF; +END$$; +-- 1) 确保存在一个测试分类 +INSERT INTO public.ml_categories (id, cid, name, created_at) +SELECT uuid_generate_v4(), nextval('public.ml_categories_cid_seq'::regclass), '测试分类-配送端', NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_categories WHERE name = '测试分类-配送端'); + +-- 2) 创建或复用商家(优先按 email 匹配,否则按任意 auth.user) +INSERT INTO public.ak_users (id, auth_id, email, username, created_at) +SELECT uuid_generate_v4(), + COALESCE((SELECT id FROM auth.users WHERE email='merchant.real@example.com' LIMIT 1),(SELECT id FROM auth.users LIMIT 1)), + 'merchant.real@example.com','real_merchant', NOW() +WHERE NOT EXISTS ( + SELECT 1 FROM public.ak_users WHERE email='merchant.real@example.com' OR auth_id = COALESCE((SELECT id FROM auth.users WHERE email='merchant.real@example.com' LIMIT 1),(SELECT id FROM auth.users LIMIT 1)) +); + +-- 3) 三个真实感顾客(按 email 或存在的 auth.users id 复用) +INSERT INTO public.ak_users (id, auth_id, email, username, created_at) +SELECT uuid_generate_v4(), COALESCE((SELECT id FROM auth.users WHERE email='zhang.san@example.com' LIMIT 1),(SELECT id FROM auth.users LIMIT 1)), 'zhang.san@example.com','张三', NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ak_users WHERE email='zhang.san@example.com' OR auth_id = COALESCE((SELECT id FROM auth.users WHERE email='zhang.san@example.com' LIMIT 1),(SELECT id FROM auth.users LIMIT 1))); + +INSERT INTO public.ak_users (id, auth_id, email, username, created_at) +SELECT uuid_generate_v4(), COALESCE((SELECT id FROM auth.users WHERE email='li.si@example.com' LIMIT 1),(SELECT id FROM auth.users LIMIT 1)), 'li.si@example.com','李四', NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ak_users WHERE email='li.si@example.com' OR auth_id = COALESCE((SELECT id FROM auth.users WHERE email='li.si@example.com' LIMIT 1),(SELECT id FROM auth.users LIMIT 1))); + +INSERT INTO public.ak_users (id, auth_id, email, username, created_at) +SELECT uuid_generate_v4(), COALESCE((SELECT id FROM auth.users WHERE email='wang.wu@example.com' LIMIT 1),(SELECT id FROM auth.users LIMIT 1)), 'wang.wu@example.com','王五', NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ak_users WHERE email='wang.wu@example.com' OR auth_id = COALESCE((SELECT id FROM auth.users WHERE email='wang.wu@example.com' LIMIT 1),(SELECT id FROM auth.users LIMIT 1))); + +-- 4) 五个商品(使用上面分类与商家) +INSERT INTO public.ml_products (id, cid, merchant_id, category_id, product_code, name, base_price, total_stock, main_image_url, created_at) +SELECT uuid_generate_v4(), nextval('public.ml_products_cid_seq'::regclass), + (SELECT id FROM public.ak_users WHERE email='merchant.real@example.com' LIMIT 1), + (SELECT id FROM public.ml_categories WHERE name='测试分类-配送端' LIMIT 1), + 'REAL-P-A-20260202','鲜榨橙汁 500ml',12.50,200,'https://cdn.example.com/orange.jpg', NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_products WHERE product_code='REAL-P-A-20260202'); + +INSERT INTO public.ml_products (id, cid, merchant_id, category_id, product_code, name, base_price, total_stock, main_image_url, created_at) +SELECT uuid_generate_v4(), nextval('public.ml_products_cid_seq'::regclass), + (SELECT id FROM public.ak_users WHERE email='merchant.real@example.com' LIMIT 1), + (SELECT id FROM public.ml_categories WHERE name='测试分类-配送端' LIMIT 1), + 'REAL-P-B-20260202','经典牛肉饼 200g',35.00,120,'https://cdn.example.com/beef.jpg', NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_products WHERE product_code='REAL-P-B-20260202'); + +INSERT INTO public.ml_products (id, cid, merchant_id, category_id, product_code, name, base_price, total_stock, main_image_url, created_at) +SELECT uuid_generate_v4(), nextval('public.ml_products_cid_seq'::regclass), + (SELECT id FROM public.ak_users WHERE email='merchant.real@example.com' LIMIT 1), + (SELECT id FROM public.ml_categories WHERE name='测试分类-配送端' LIMIT 1), + 'REAL-P-C-20260202','手工三明治',22.00,80,'https://cdn.example.com/sandwich.jpg', NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_products WHERE product_code='REAL-P-C-20260202'); + +INSERT INTO public.ml_products (id, cid, merchant_id, category_id, product_code, name, base_price, total_stock, main_image_url, created_at) +SELECT uuid_generate_v4(), nextval('public.ml_products_cid_seq'::regclass), + (SELECT id FROM public.ak_users WHERE email='merchant.real@example.com' LIMIT 1), + (SELECT id FROM public.ml_categories WHERE name='测试分类-配送端' LIMIT 1), + 'REAL-P-D-20260202','每日现磨咖啡',18.00,150,'https://cdn.example.com/coffee.jpg', NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_products WHERE product_code='REAL-P-D-20260202'); + +-- 5) 创建若干订单与配送任务(status = 1, driver_id = NULL) +-- 订单 1(示例已更新:order_no / phone / address) +INSERT INTO public.ml_orders (order_no, user_id, merchant_id, product_amount, shipping_fee, total_amount, shipping_address, created_at, updated_at) +SELECT 'TEST-DELIV-20260202-001', + COALESCE( + (SELECT id FROM public.ak_users WHERE email='zhang.san@example.com' LIMIT 1), + (SELECT id FROM public.ak_users WHERE auth_id=(SELECT id FROM auth.users WHERE email='zhang.san@example.com' LIMIT 1) LIMIT 1), + (SELECT id FROM public.ak_users LIMIT 1) + ), + (SELECT id FROM public.ak_users WHERE email='merchant.real@example.com' LIMIT 1), + 12.50,3.00,15.50, + ('{"contact":"张三","phone":"13890001111","province":"北京市","city":"北京市","district":"朝阳区","street":"望京街道","detail":"望京SOHO 1号楼"}')::jsonb, + NOW(), NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_orders WHERE order_no='TEST-DELIV-20260202-001'); + +INSERT INTO public.ml_order_items (id, order_id, product_id, product_name, price, quantity, total_amount, created_at) +SELECT uuid_generate_v4(), (SELECT id FROM public.ml_orders WHERE order_no='TEST-DELIV-20260202-001' LIMIT 1), (SELECT id FROM public.ml_products WHERE product_code='REAL-P-A-20260202' LIMIT 1), '鲜榨橙汁 500ml',12.50,1,12.50,NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_order_items oi JOIN public.ml_orders o ON oi.order_id=o.id WHERE o.order_no='TEST-DELIV-20260202-001'); + +INSERT INTO public.ml_delivery_tasks (order_id, pickup_address, delivery_address, delivery_fee, status, created_at, updated_at) +SELECT (SELECT id FROM public.ml_orders WHERE order_no='TEST-DELIV-20260202-001' LIMIT 1), + ('{"contact":"门店A","phone":"13990001111","detail":"门店A 地址"}')::jsonb, + ('{"contact":"张三","phone":"13890001111","detail":"望京SOHO 1号楼"}')::jsonb, + 3.00,1,NOW(),NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_delivery_tasks dt JOIN public.ml_orders o ON dt.order_id=o.id WHERE o.order_no='TEST-DELIV-20260202-001'); + +-- 订单 2(示例已更新) +INSERT INTO public.ml_orders (order_no, user_id, merchant_id, product_amount, shipping_fee, total_amount, shipping_address, created_at, updated_at) +SELECT 'TEST-DELIV-20260202-002', + COALESCE( + (SELECT id FROM public.ak_users WHERE email='li.si@example.com' LIMIT 1), + (SELECT id FROM public.ak_users WHERE auth_id=(SELECT id FROM auth.users WHERE email='li.si@example.com' LIMIT 1) LIMIT 1), + (SELECT id FROM public.ak_users LIMIT 1) + ), + (SELECT id FROM public.ak_users WHERE email='merchant.real@example.com' LIMIT 1), + 35.00,4.00,39.00, + ('{"contact":"李四","phone":"13890002222","province":"上海市","city":"上海市","district":"静安区","street":"南京西路","detail":"静安寺附近"}')::jsonb, + NOW(), NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_orders WHERE order_no='TEST-DELIV-20260202-002'); + +INSERT INTO public.ml_order_items (id, order_id, product_id, product_name, price, quantity, total_amount, created_at) +SELECT uuid_generate_v4(), (SELECT id FROM public.ml_orders WHERE order_no='TEST-DELIV-20260202-002' LIMIT 1), (SELECT id FROM public.ml_products WHERE product_code='REAL-P-B-20260202' LIMIT 1), '经典牛肉饼 200g',35.00,1,35.00,NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_order_items oi JOIN public.ml_orders o ON oi.order_id=o.id WHERE o.order_no='TEST-DELIV-20260202-002'); + +INSERT INTO public.ml_delivery_tasks (order_id, pickup_address, delivery_address, delivery_fee, status, created_at, updated_at) +SELECT (SELECT id FROM public.ml_orders WHERE order_no='TEST-DELIV-20260202-002' LIMIT 1), + ('{"contact":"门店B","phone":"13990002222","detail":"门店B 地址"}')::jsonb, + ('{"contact":"李四","phone":"13890002222","detail":"静安寺附近"}')::jsonb, + 4.00,1,NOW(),NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_delivery_tasks dt JOIN public.ml_orders o ON dt.order_id=o.id WHERE o.order_no='TEST-DELIV-20260202-002'); + +-- 订单 3(示例已更新) +INSERT INTO public.ml_orders (order_no, user_id, merchant_id, product_amount, shipping_fee, total_amount, shipping_address, created_at, updated_at) +SELECT 'TEST-DELIV-20260202-003', + COALESCE( + (SELECT id FROM public.ak_users WHERE email='wang.wu@example.com' LIMIT 1), + (SELECT id FROM public.ak_users WHERE auth_id=(SELECT id FROM auth.users WHERE email='wang.wu@example.com' LIMIT 1) LIMIT 1), + (SELECT id FROM public.ak_users LIMIT 1) + ), + (SELECT id FROM public.ak_users WHERE email='merchant.real@example.com' LIMIT 1), + 22.00,3.50,25.50, + ('{"contact":"王五","phone":"13890003333","province":"广东省","city":"广州市","district":"天河区","street":"体育西路","detail":"天河城附近"}')::jsonb, + NOW(), NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_orders WHERE order_no='TEST-DELIV-20260202-003'); + +INSERT INTO public.ml_order_items (id, order_id, product_id, product_name, price, quantity, total_amount, created_at) +SELECT uuid_generate_v4(), (SELECT id FROM public.ml_orders WHERE order_no='TEST-DELIV-20260202-003' LIMIT 1), (SELECT id FROM public.ml_products WHERE product_code='REAL-P-C-20260202' LIMIT 1), '手工三明治',22.00,1,22.00,NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_order_items oi JOIN public.ml_orders o ON oi.order_id=o.id WHERE o.order_no='TEST-DELIV-20260202-003'); + +INSERT INTO public.ml_delivery_tasks (order_id, pickup_address, delivery_address, delivery_fee, status, created_at, updated_at) +SELECT (SELECT id FROM public.ml_orders WHERE order_no='TEST-DELIV-20260202-003' LIMIT 1), + ('{"contact":"门店C","phone":"13990003333","detail":"门店C 地址"}')::jsonb, + ('{"contact":"王五","phone":"13890003333","detail":"天河城附近"}')::jsonb, + 3.50,1,NOW(),NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_delivery_tasks dt JOIN public.ml_orders o ON dt.order_id=o.id WHERE o.order_no='TEST-DELIV-20260202-003'); + +-- 订单 4(示例已更新) +INSERT INTO public.ml_orders (order_no, user_id, merchant_id, product_amount, shipping_fee, total_amount, shipping_address, created_at, updated_at) +SELECT 'TEST-DELIV-20260202-004', + COALESCE( + (SELECT id FROM public.ak_users WHERE email='zhang.san@example.com' LIMIT 1), + (SELECT id FROM public.ak_users WHERE auth_id=(SELECT id FROM auth.users WHERE email='zhang.san@example.com' LIMIT 1) LIMIT 1), + (SELECT id FROM public.ak_users LIMIT 1) + ), + (SELECT id FROM public.ak_users WHERE email='merchant.real@example.com' LIMIT 1), + 18.00,3.00,21.00, + ('{"contact":"张三","phone":"13890001111","province":"上海市","city":"上海市","district":"浦东新区","street":"世纪大道","detail":"世纪汇 10 号"}')::jsonb, + NOW(), NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_orders WHERE order_no='TEST-DELIV-20260202-004'); + +INSERT INTO public.ml_order_items (id, order_id, product_id, product_name, price, quantity, total_amount, created_at) +SELECT uuid_generate_v4(), (SELECT id FROM public.ml_orders WHERE order_no='TEST-DELIV-20260202-004' LIMIT 1), (SELECT id FROM public.ml_products WHERE product_code='REAL-P-D-20260202' LIMIT 1), '每日现磨咖啡',18.00,1,18.00,NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_order_items oi JOIN public.ml_orders o ON oi.order_id=o.id WHERE o.order_no='TEST-DELIV-20260202-004'); + +INSERT INTO public.ml_delivery_tasks (order_id, pickup_address, delivery_address, delivery_fee, status, created_at, updated_at) +SELECT (SELECT id FROM public.ml_orders WHERE order_no='TEST-DELIV-20260202-004' LIMIT 1), + ('{"contact":"门店D","phone":"13990004444","detail":"门店D 地址"}')::jsonb, + ('{"contact":"张三","phone":"13890001111","detail":"世纪汇 10 号"}')::jsonb, + 3.00,1,NOW(),NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_delivery_tasks dt JOIN public.ml_orders o ON dt.order_id=o.id WHERE o.order_no='TEST-DELIV-20260202-004'); + +-- 最终返回已创建或已存在的关键 id,便于验证 +SELECT + (SELECT id FROM public.ak_users WHERE email='merchant.real@example.com' LIMIT 1) AS merchant_id, + (SELECT id FROM public.ak_users WHERE email='zhang.san@example.com' LIMIT 1) AS custA_id, + (SELECT id FROM public.ak_users WHERE email='li.si@example.com' LIMIT 1) AS custB_id, + (SELECT id FROM public.ak_users WHERE email='wang.wu@example.com' LIMIT 1) AS custC_id, + (SELECT id FROM public.ml_products WHERE product_code='REAL-P-A-20260202' LIMIT 1) AS productA_id, + (SELECT id FROM public.ml_products WHERE product_code='REAL-P-B-20260202' LIMIT 1) AS productB_id, + (SELECT id FROM public.ml_products WHERE product_code='REAL-P-C-20260202' LIMIT 1) AS productC_id, + (SELECT id FROM public.ml_products WHERE product_code='REAL-P-D-20260202' LIMIT 1) AS productD_id, + (SELECT id FROM public.ml_orders WHERE order_no='TEST-DELIV-20260202-001' LIMIT 1) AS order1_id, + (SELECT id FROM public.ml_orders WHERE order_no='TEST-DELIV-20260202-002' LIMIT 1) AS order2_id, + (SELECT id FROM public.ml_orders WHERE order_no='TEST-DELIV-20260202-003' LIMIT 1) AS order3_id, + (SELECT id FROM public.ml_orders WHERE order_no='TEST-DELIV-20260202-004' LIMIT 1) AS order4_id; + +-- 6) 批量生成 20 个“待接取”订单(幂等) +-- 订单号格式:PENDING-20260202-001 .. PENDING-20260202-020 +INSERT INTO public.ml_orders (order_no, user_id, merchant_id, product_amount, shipping_fee, total_amount, shipping_address, created_at, updated_at) +SELECT t.order_no, t.user_id, t.merchant_id, t.product_amount, t.shipping_fee, t.total_amount, t.shipping_address, NOW(), NOW() +FROM ( + SELECT format('PENDING-20260202-%s', lpad(i::text,3,'0')) AS order_no, + COALESCE( + CASE (i % 3) + WHEN 1 THEN (SELECT id FROM public.ak_users WHERE email='zhang.san@example.com' LIMIT 1) + WHEN 2 THEN (SELECT id FROM public.ak_users WHERE email='li.si@example.com' LIMIT 1) + ELSE (SELECT id FROM public.ak_users WHERE email='wang.wu@example.com' LIMIT 1) + END, + (SELECT id FROM public.ak_users LIMIT 1) + ) AS user_id, + (SELECT id FROM public.ak_users WHERE email='merchant.real@example.com' LIMIT 1) AS merchant_id, + (SELECT base_price FROM public.ml_products WHERE product_code='REAL-P-A-20260202' LIMIT 1) AS product_amount, + 3.00 AS shipping_fee, + (SELECT base_price FROM public.ml_products WHERE product_code='REAL-P-A-20260202' LIMIT 1) + 3.00 AS total_amount, + jsonb_build_object('contact', CASE WHEN (i % 3)=1 THEN '张三' WHEN (i % 3)=2 THEN '李四' ELSE '王五' END, 'phone', '138900' || lpad(i::text,5,'0'), 'detail', '自动生成地址 ' || i) AS shipping_address + FROM generate_series(1,20) AS s(i) +) AS t +WHERE NOT EXISTS (SELECT 1 FROM public.ml_orders o WHERE o.order_no = t.order_no); + +-- 生成对应的 order_items(若不存在) +INSERT INTO public.ml_order_items (id, order_id, product_id, product_name, price, quantity, total_amount, created_at) +SELECT uuid_generate_v4(), o.id, p.id, p.name, p.base_price, 1, p.base_price, NOW() +FROM public.ml_orders o +JOIN public.ml_products p ON p.product_code = 'REAL-P-A-20260202' +WHERE o.order_no LIKE 'PENDING-20260202-%' + AND NOT EXISTS (SELECT 1 FROM public.ml_order_items oi WHERE oi.order_id = o.id); + +-- 生成对应的 delivery_tasks(status = 1) +WITH no AS ( + SELECT id, order_no, shipping_address, ROW_NUMBER() OVER (ORDER BY id) AS rn + FROM public.ml_orders WHERE order_no LIKE 'PENDING-20260202-%' +) +INSERT INTO public.ml_delivery_tasks (order_id, pickup_address, delivery_address, delivery_fee, status, created_at, updated_at) +SELECT no.id, + jsonb_build_object('contact','自动门店','phone', '13900' || lpad(no.rn::text,4,'0'),'detail','自动门店地址')::jsonb, + no.shipping_address, + 3.00,1,NOW(),NOW() +FROM no +WHERE NOT EXISTS (SELECT 1 FROM public.ml_delivery_tasks dt WHERE dt.order_id = no.id); +-- realistic_mock_data.sql +-- 幂等脚本:在 dev 环境创建更真实的测试数据 +-- 使用说明:在 Supabase SQL Editor 中选择 Role = postgres,整体执行此文件。 + +-- 运行前确保至少存在一个 auth 用户,否则后续插入会违背 FK +DO $$ +BEGIN + IF NOT EXISTS (SELECT 1 FROM auth.users) THEN + RAISE EXCEPTION 'No auth.users found. Create at least one auth user in Supabase auth or sign up once, then re-run this script.'; + END IF; +END$$; +-- 1) 确保存在一个测试分类 +INSERT INTO public.ml_categories (id, cid, name, created_at) +SELECT uuid_generate_v4(), nextval('public.ml_categories_cid_seq'::regclass), '测试分类-配送端', NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_categories WHERE name = '测试分类-配送端'); + +-- 2) 创建或复用商家(优先按 email 匹配,否则按任意 auth.user) +INSERT INTO public.ak_users (id, auth_id, email, username, created_at) +SELECT uuid_generate_v4(), + COALESCE((SELECT id FROM auth.users WHERE email='merchant.real@example.com' LIMIT 1),(SELECT id FROM auth.users LIMIT 1)), + 'merchant.real@example.com','real_merchant', NOW() +WHERE NOT EXISTS ( + SELECT 1 FROM public.ak_users WHERE email='merchant.real@example.com' OR auth_id = COALESCE((SELECT id FROM auth.users WHERE email='merchant.real@example.com' LIMIT 1),(SELECT id FROM auth.users LIMIT 1)) +); + +-- 3) 三个真实感顾客(按 email 或存在的 auth.users id 复用) +INSERT INTO public.ak_users (id, auth_id, email, username, created_at) +SELECT uuid_generate_v4(), COALESCE((SELECT id FROM auth.users WHERE email='zhang.san@example.com' LIMIT 1),(SELECT id FROM auth.users LIMIT 1)), 'zhang.san@example.com','张三', NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ak_users WHERE email='zhang.san@example.com' OR auth_id = COALESCE((SELECT id FROM auth.users WHERE email='zhang.san@example.com' LIMIT 1),(SELECT id FROM auth.users LIMIT 1))); + +INSERT INTO public.ak_users (id, auth_id, email, username, created_at) +SELECT uuid_generate_v4(), COALESCE((SELECT id FROM auth.users WHERE email='li.si@example.com' LIMIT 1),(SELECT id FROM auth.users LIMIT 1)), 'li.si@example.com','李四', NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ak_users WHERE email='li.si@example.com' OR auth_id = COALESCE((SELECT id FROM auth.users WHERE email='li.si@example.com' LIMIT 1),(SELECT id FROM auth.users LIMIT 1))); + +INSERT INTO public.ak_users (id, auth_id, email, username, created_at) +SELECT uuid_generate_v4(), COALESCE((SELECT id FROM auth.users WHERE email='wang.wu@example.com' LIMIT 1),(SELECT id FROM auth.users LIMIT 1)), 'wang.wu@example.com','王五', NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ak_users WHERE email='wang.wu@example.com' OR auth_id = COALESCE((SELECT id FROM auth.users WHERE email='wang.wu@example.com' LIMIT 1),(SELECT id FROM auth.users LIMIT 1))); + +-- 4) 五个商品(使用上面分类与商家) +INSERT INTO public.ml_products (id, cid, merchant_id, category_id, product_code, name, base_price, total_stock, main_image_url, created_at) +SELECT uuid_generate_v4(), nextval('public.ml_products_cid_seq'::regclass), + (SELECT id FROM public.ak_users WHERE email='merchant.real@example.com' LIMIT 1), + (SELECT id FROM public.ml_categories WHERE name='测试分类-配送端' LIMIT 1), + 'REAL-P-A-20260202','鲜榨橙汁 500ml',12.50,200,'https://cdn.example.com/orange.jpg', NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_products WHERE product_code='REAL-P-A-20260202'); + +INSERT INTO public.ml_products (id, cid, merchant_id, category_id, product_code, name, base_price, total_stock, main_image_url, created_at) +SELECT uuid_generate_v4(), nextval('public.ml_products_cid_seq'::regclass), + (SELECT id FROM public.ak_users WHERE email='merchant.real@example.com' LIMIT 1), + (SELECT id FROM public.ml_categories WHERE name='测试分类-配送端' LIMIT 1), + 'REAL-P-B-20260202','经典牛肉饼 200g',35.00,120,'https://cdn.example.com/beef.jpg', NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_products WHERE product_code='REAL-P-B-20260202'); + +INSERT INTO public.ml_products (id, cid, merchant_id, category_id, product_code, name, base_price, total_stock, main_image_url, created_at) +SELECT uuid_generate_v4(), nextval('public.ml_products_cid_seq'::regclass), + (SELECT id FROM public.ak_users WHERE email='merchant.real@example.com' LIMIT 1), + (SELECT id FROM public.ml_categories WHERE name='测试分类-配送端' LIMIT 1), + 'REAL-P-C-20260202','手工三明治',22.00,80,'https://cdn.example.com/sandwich.jpg', NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_products WHERE product_code='REAL-P-C-20260202'); + +INSERT INTO public.ml_products (id, cid, merchant_id, category_id, product_code, name, base_price, total_stock, main_image_url, created_at) +SELECT uuid_generate_v4(), nextval('public.ml_products_cid_seq'::regclass), + (SELECT id FROM public.ak_users WHERE email='merchant.real@example.com' LIMIT 1), + (SELECT id FROM public.ml_categories WHERE name='测试分类-配送端' LIMIT 1), + 'REAL-P-D-20260202','每日现磨咖啡',18.00,150,'https://cdn.example.com/coffee.jpg', NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_products WHERE product_code='REAL-P-D-20260202'); + +-- 5) 创建若干订单与配送任务(status = 1, driver_id = NULL) +-- 订单 1 +INSERT INTO public.ml_orders (order_no, user_id, merchant_id, product_amount, shipping_fee, total_amount, shipping_address, created_at, updated_at) +SELECT 'REAL-ORD-20260202-001', + COALESCE( + (SELECT id FROM public.ak_users WHERE email='zhang.san@example.com' LIMIT 1), + (SELECT id FROM public.ak_users WHERE auth_id=(SELECT id FROM auth.users WHERE email='zhang.san@example.com' LIMIT 1) LIMIT 1), + (SELECT id FROM public.ak_users LIMIT 1) + ), + (SELECT id FROM public.ak_users WHERE email='merchant.real@example.com' LIMIT 1), + 12.50,3.00,15.50, + ('{"contact":"张三","phone":"13811112222","province":"北京市","city":"北京市","district":"朝阳区","street":"望京街道","detail":"望京SOHO 1号楼"}')::jsonb, + NOW(), NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_orders WHERE order_no='REAL-ORD-20260202-001'); + +INSERT INTO public.ml_order_items (id, order_id, product_id, product_name, price, quantity, total_amount, created_at) +SELECT uuid_generate_v4(), (SELECT id FROM public.ml_orders WHERE order_no='REAL-ORD-20260202-001' LIMIT 1), (SELECT id FROM public.ml_products WHERE product_code='REAL-P-A-20260202' LIMIT 1), '鲜榨橙汁 500ml',12.50,1,12.50,NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_order_items oi JOIN public.ml_orders o ON oi.order_id=o.id WHERE o.order_no='REAL-ORD-20260202-001'); + +INSERT INTO public.ml_delivery_tasks (order_id, pickup_address, delivery_address, delivery_fee, status, created_at, updated_at) +SELECT (SELECT id FROM public.ml_orders WHERE order_no='REAL-ORD-20260202-001' LIMIT 1), + ('{"contact":"门店A","phone":"13920001111","detail":"门店A 地址"}')::jsonb, + ('{"contact":"张三","phone":"13811112222","detail":"望京SOHO 1号楼"}')::jsonb, + 3.00,1,NOW(),NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_delivery_tasks dt JOIN public.ml_orders o ON dt.order_id=o.id WHERE o.order_no='REAL-ORD-20260202-001'); + +-- 订单 2 +INSERT INTO public.ml_orders (order_no, user_id, merchant_id, product_amount, shipping_fee, total_amount, shipping_address, created_at, updated_at) +SELECT 'REAL-ORD-20260202-002', + COALESCE( + (SELECT id FROM public.ak_users WHERE email='li.si@example.com' LIMIT 1), + (SELECT id FROM public.ak_users WHERE auth_id=(SELECT id FROM auth.users WHERE email='li.si@example.com' LIMIT 1) LIMIT 1), + (SELECT id FROM public.ak_users LIMIT 1) + ), + (SELECT id FROM public.ak_users WHERE email='merchant.real@example.com' LIMIT 1), + 35.00,4.00,39.00, + ('{"contact":"李四","phone":"13822223333","province":"上海市","city":"上海市","district":"静安区","street":"南京西路","detail":"静安寺附近"}')::jsonb, + NOW(), NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_orders WHERE order_no='REAL-ORD-20260202-002'); + +INSERT INTO public.ml_order_items (id, order_id, product_id, product_name, price, quantity, total_amount, created_at) +SELECT uuid_generate_v4(), (SELECT id FROM public.ml_orders WHERE order_no='REAL-ORD-20260202-002' LIMIT 1), (SELECT id FROM public.ml_products WHERE product_code='REAL-P-B-20260202' LIMIT 1), '经典牛肉饼 200g',35.00,1,35.00,NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_order_items oi JOIN public.ml_orders o ON oi.order_id=o.id WHERE o.order_no='REAL-ORD-20260202-002'); + +INSERT INTO public.ml_delivery_tasks (order_id, pickup_address, delivery_address, delivery_fee, status, created_at, updated_at) +SELECT (SELECT id FROM public.ml_orders WHERE order_no='REAL-ORD-20260202-002' LIMIT 1), + ('{"contact":"门店B","phone":"13920002222","detail":"门店B 地址"}')::jsonb, + ('{"contact":"李四","phone":"13822223333","detail":"静安寺附近"}')::jsonb, + 4.00,1,NOW(),NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_delivery_tasks dt JOIN public.ml_orders o ON dt.order_id=o.id WHERE o.order_no='REAL-ORD-20260202-002'); + +-- 订单 3 +INSERT INTO public.ml_orders (order_no, user_id, merchant_id, product_amount, shipping_fee, total_amount, shipping_address, created_at, updated_at) +SELECT 'REAL-ORD-20260202-003', + COALESCE( + (SELECT id FROM public.ak_users WHERE email='wang.wu@example.com' LIMIT 1), + (SELECT id FROM public.ak_users WHERE auth_id=(SELECT id FROM auth.users WHERE email='wang.wu@example.com' LIMIT 1) LIMIT 1), + (SELECT id FROM public.ak_users LIMIT 1) + ), + (SELECT id FROM public.ak_users WHERE email='merchant.real@example.com' LIMIT 1), + 22.00,3.50,25.50, + ('{"contact":"王五","phone":"13833334444","province":"广东省","city":"广州市","district":"天河区","street":"体育西路","detail":"天河城附近"}')::jsonb, + NOW(), NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_orders WHERE order_no='REAL-ORD-20260202-003'); + +INSERT INTO public.ml_order_items (id, order_id, product_id, product_name, price, quantity, total_amount, created_at) +SELECT uuid_generate_v4(), (SELECT id FROM public.ml_orders WHERE order_no='REAL-ORD-20260202-003' LIMIT 1), (SELECT id FROM public.ml_products WHERE product_code='REAL-P-C-20260202' LIMIT 1), '手工三明治',22.00,1,22.00,NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_order_items oi JOIN public.ml_orders o ON oi.order_id=o.id WHERE o.order_no='REAL-ORD-20260202-003'); + +INSERT INTO public.ml_delivery_tasks (order_id, pickup_address, delivery_address, delivery_fee, status, created_at, updated_at) +SELECT (SELECT id FROM public.ml_orders WHERE order_no='REAL-ORD-20260202-003' LIMIT 1), + ('{"contact":"门店C","phone":"13920003333","detail":"门店C 地址"}')::jsonb, + ('{"contact":"王五","phone":"13833334444","detail":"天河城附近"}')::jsonb, + 3.50,1,NOW(),NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_delivery_tasks dt JOIN public.ml_orders o ON dt.order_id=o.id WHERE o.order_no='REAL-ORD-20260202-003'); + +-- 订单 4 +INSERT INTO public.ml_orders (order_no, user_id, merchant_id, product_amount, shipping_fee, total_amount, shipping_address, created_at, updated_at) +SELECT 'REAL-ORD-20260202-004', + COALESCE( + (SELECT id FROM public.ak_users WHERE email='zhang.san@example.com' LIMIT 1), + (SELECT id FROM public.ak_users WHERE auth_id=(SELECT id FROM auth.users WHERE email='zhang.san@example.com' LIMIT 1) LIMIT 1), + (SELECT id FROM public.ak_users LIMIT 1) + ), + (SELECT id FROM public.ak_users WHERE email='merchant.real@example.com' LIMIT 1), + 18.00,3.00,21.00, + ('{"contact":"张三","phone":"13811112222","province":"上海市","city":"上海市","district":"浦东新区","street":"世纪大道","detail":"世纪汇 10 号"}')::jsonb, + NOW(), NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_orders WHERE order_no='REAL-ORD-20260202-004'); + +INSERT INTO public.ml_order_items (id, order_id, product_id, product_name, price, quantity, total_amount, created_at) +SELECT uuid_generate_v4(), (SELECT id FROM public.ml_orders WHERE order_no='REAL-ORD-20260202-004' LIMIT 1), (SELECT id FROM public.ml_products WHERE product_code='REAL-P-D-20260202' LIMIT 1), '每日现磨咖啡',18.00,1,18.00,NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_order_items oi JOIN public.ml_orders o ON oi.order_id=o.id WHERE o.order_no='REAL-ORD-20260202-004'); + +INSERT INTO public.ml_delivery_tasks (order_id, pickup_address, delivery_address, delivery_fee, status, created_at, updated_at) +SELECT (SELECT id FROM public.ml_orders WHERE order_no='REAL-ORD-20260202-004' LIMIT 1), + ('{"contact":"门店D","phone":"13920004444","detail":"门店D 地址"}')::jsonb, + ('{"contact":"张三","phone":"13811112222","detail":"世纪汇 10 号"}')::jsonb, + 3.00,1,NOW(),NOW() +WHERE NOT EXISTS (SELECT 1 FROM public.ml_delivery_tasks dt JOIN public.ml_orders o ON dt.order_id=o.id WHERE o.order_no='REAL-ORD-20260202-004'); + +-- 最终返回已创建或已存在的关键 id,便于验证 +SELECT + (SELECT id FROM public.ak_users WHERE email='merchant.real@example.com' LIMIT 1) AS merchant_id, + (SELECT id FROM public.ak_users WHERE email='zhang.san@example.com' LIMIT 1) AS custA_id, + (SELECT id FROM public.ak_users WHERE email='li.si@example.com' LIMIT 1) AS custB_id, + (SELECT id FROM public.ak_users WHERE email='wang.wu@example.com' LIMIT 1) AS custC_id, + (SELECT id FROM public.ml_products WHERE product_code='REAL-P-A-20260202' LIMIT 1) AS productA_id, + (SELECT id FROM public.ml_products WHERE product_code='REAL-P-B-20260202' LIMIT 1) AS productB_id, + (SELECT id FROM public.ml_products WHERE product_code='REAL-P-C-20260202' LIMIT 1) AS productC_id, + (SELECT id FROM public.ml_products WHERE product_code='REAL-P-D-20260202' LIMIT 1) AS productD_id, + (SELECT id FROM public.ml_orders WHERE order_no='REAL-ORD-20260202-001' LIMIT 1) AS order1_id, + (SELECT id FROM public.ml_orders WHERE order_no='REAL-ORD-20260202-002' LIMIT 1) AS order2_id, + (SELECT id FROM public.ml_orders WHERE order_no='REAL-ORD-20260202-003' LIMIT 1) AS order3_id, + (SELECT id FROM public.ml_orders WHERE order_no='REAL-ORD-20260202-004' LIMIT 1) AS order4_id; From 3922409a251d6c6e7bdbc704cb940bbfffadbc18 Mon Sep 17 00:00:00 2001 From: huangzhenbao <17818024429@163.com> Date: Tue, 3 Feb 2026 21:35:57 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/admin/ADMIN_MANAGEMENT_GUIDE.md | 594 ------ docs/admin/CRMEB_DASHBOARD_GUIDE.md | 475 ----- docs/admin/CRMEB_TO_UVUE_MIGRATION_GUIDE.md | 807 --------- docs/admin/FRONTEND_ARCHITECTURE_ANALYSIS.md | 427 ----- docs/admin/PAGE_STRUCTURE_ANALYSIS.md | 292 --- docs/admin/UNI_APP_X_PAGE_FIX_GUIDE.md | 1612 ----------------- layouts/admin/router/adminComponentMap.uts | 175 +- layouts/admin/router/adminRoutes.uts | 820 +++++++-- pages/mall/admin/cms/article/list.uvue | 419 ++++- pages/mall/admin/cms/category/list.uvue | 309 +++- .../admin/customer-service/auto-reply.uvue | 98 - pages/mall/admin/customer-service/config.uvue | 98 - pages/mall/admin/customer-service/list.uvue | 97 - .../mall/admin/customer-service/messages.uvue | 98 - pages/mall/admin/customer-service/script.uvue | 98 - pages/mall/admin/decoration/category.uvue | 385 ++++ pages/mall/admin/decoration/home.uvue | 725 ++++++++ pages/mall/admin/decoration/user.uvue | 566 ++++++ .../mall/admin/docs}/00_READ_ME_FIRST.md | 0 .../mall/admin/docs}/ADMIN_LAYOUT_GUIDE.md | 0 .../ADMIN_LAYOUT_IMPLEMENTATION_COMPLETE.md | 0 .../docs}/ADMIN_LAYOUT_PROGRESS_REPORT.md | 0 ...DMIN_LAYOUT_TRANSFORMATION_100_COMPLETE.md | 0 .../ADMIN_LAYOUT_TRANSFORMATION_COMPLETE.md | 0 .../admin/docs}/ADMIN_MANAGEMENT_GUIDE.md | 0 .../docs}/ADMIN_PAGES_REFACTORING_PLAN.md | 0 .../mall/admin/docs}/ADMIN_PAGE_CHECKLIST.csv | 0 .../mall/admin/docs}/ADMIN_PAGE_COMPLETE.md | 0 .../docs}/ADMIN_PAGE_COMPLIANCE_CHECKLIST.md | 0 .../mall/admin/docs}/ADMIN_PAGE_INDEX.md | 0 .../docs}/ADMIN_PAGE_MODIFICATION_PLAN.md | 0 .../admin/docs}/ADMIN_PAGE_QUICK_REFERENCE.md | 0 .../mall/admin/docs}/ADMIN_PAGE_START_HERE.md | 0 .../mall/admin/docs}/ADMIN_PAGE_SUMMARY.md | 0 .../admin/docs}/ADMIN_PROJECT_FINAL_REPORT.md | 0 .../mall/admin/docs}/ADMIN_REFACTOR_INDEX.md | 0 .../admin/docs}/ADMIN_REFACTOR_PROGRESS.md | 0 .../admin/docs}/COMPONENT_SPECIFICATION.md | 0 .../mall/admin/docs}/CRMEB_DASHBOARD_GUIDE.md | 0 .../docs}/CRMEB_TO_UVUE_MIGRATION_GUIDE.md | 0 .../admin/docs}/CRMEB_UVUE_MIGRATION_GUIDE.md | 0 .../mall/admin/docs}/DELIVERY_SUMMARY.md | 0 .../admin/docs}/DESIGN_DECORATION_GUIDE.md | 0 .../docs}/DESIGN_IMPLEMENTATION_REPORT.md | 0 .../docs}/DESIGN_MODULE_UPGRADE_REPORT.md | 0 .../admin/docs}/DESIGN_MODULE_USER_GUIDE.md | 0 .../admin/docs}/DESIGN_QUICK_REFERENCE.md | 0 .../admin/docs}/ENGINEERING_BEST_PRACTICES.md | 0 .../docs}/FRONTEND_ARCHITECTURE_ANALYSIS.md | 0 .../admin/docs}/IMPLEMENTATION_ROADMAP.md | 0 .../ORDER_MENU_HIGHLIGHT_COMPLETION_REPORT.md | 0 .../admin/docs}/ORDER_MENU_HIGHLIGHT_FIX.md | 0 .../docs}/ORDER_MENU_HIGHLIGHT_QUICK_FIX.md | 0 .../mall/admin/docs}/PAGES_ROUTES.md | 0 .../admin/docs}/PAGE_STRUCTURE_ANALYSIS.md | 0 .../docs}/PAGE_STRUCTURE_SPECIFICATION.md | 0 .../admin/docs}/PROJECT_COMPLETION_REPORT.md | 0 .../mall/admin/docs}/QUICK_REFERENCE.md | 0 .../docs}/QUICK_START_NEW_DEVELOPMENT.md | 0 .../admin => pages/mall/admin/docs}/README.md | 0 .../mall/admin/docs}/REFACTOR_BEFORE_AFTER.md | 0 .../mall/admin/docs}/REFACTOR_SUMMARY.md | 0 .../admin/docs}/SERVICE_DELIVERY_CHECKLIST.md | 0 .../docs}/SERVICE_MODULE_IMPLEMENTATION.md | 0 .../admin/docs}/SERVICE_PROJECT_SUMMARY.md | 0 .../mall/admin/docs}/SERVICE_QUICK_START.md | 0 .../mall/admin/docs}/STYLE_SPECIFICATION.md | 0 .../mall/admin/docs}/SYSTEM_INFO_FIX_GUIDE.md | 0 .../admin/docs}/SYSTEM_INFO_ROOT_CAUSE.md | 0 .../admin/docs}/SYSTEM_INFO_SIDEBAR_FIX.md | 0 .../admin/docs}/UNI_APP_X_PAGE_FIX_GUIDE.md | 0 pages/mall/admin/finance/balance_record.uvue | 247 +++ pages/mall/admin/finance/balance_stats.uvue | 541 ++++++ pages/mall/admin/finance/bill.uvue | 422 +++++ pages/mall/admin/finance/capital_flow.uvue | 317 ++++ pages/mall/admin/finance/commission.uvue | 358 ++++ .../admin/finance/finance-placeholder.scss | 55 + pages/mall/admin/finance/invoice.uvue | 394 ++++ pages/mall/admin/finance/recharge.uvue | 425 +++++ .../mall/admin/finance/transaction_stats.uvue | 836 +++++++++ pages/mall/admin/finance/withdrawal.uvue | 469 +++++ pages/mall/admin/homePage/index.uvue.bak | 483 ----- pages/mall/admin/kefu/config.uvue | 317 ++++ pages/mall/admin/kefu/feedback.uvue | 347 ++++ pages/mall/admin/kefu/list.uvue | 324 ++++ pages/mall/admin/kefu/words.uvue | 626 +++++++ pages/mall/admin/maintain/dev/config.uvue | 57 + pages/mall/admin/marketing/coupon/list.uvue | 351 +++- pages/mall/admin/marketing/coupon/user.uvue | 230 +++ .../admin/marketing/integral/statistic.uvue | 480 +++++ .../admin/order/aftersales-order/index.uvue | 405 ++++- .../mall/admin/order/cashier-order/index.uvue | 391 +++- .../order/order-configuration/index.uvue | 462 ++++- .../admin/order/write-off-records/index.uvue | 366 +++- pages/mall/admin/product-statistics.uvue | 65 - .../product/product-management/edit.uvue | 347 ++++ .../product/product-management/index.uvue | 619 ++++++- .../product-management/member-price.uvue | 68 + .../product/product-statistics/index.uvue | 572 +++++- pages/mall/admin/product/reply.uvue | 277 ++- pages/mall/admin/user/group.uvue | 489 ++++- pages/mall/admin/user/label.uvue | 483 ++++- pages/mall/admin/user/level.uvue | 553 +++++- pages/mall/admin/user/list.uvue | 123 +- search_encoding.py | 25 + 105 files changed, 14758 insertions(+), 5861 deletions(-) delete mode 100644 docs/admin/ADMIN_MANAGEMENT_GUIDE.md delete mode 100644 docs/admin/CRMEB_DASHBOARD_GUIDE.md delete mode 100644 docs/admin/CRMEB_TO_UVUE_MIGRATION_GUIDE.md delete mode 100644 docs/admin/FRONTEND_ARCHITECTURE_ANALYSIS.md delete mode 100644 docs/admin/PAGE_STRUCTURE_ANALYSIS.md delete mode 100644 docs/admin/UNI_APP_X_PAGE_FIX_GUIDE.md delete mode 100644 pages/mall/admin/customer-service/auto-reply.uvue delete mode 100644 pages/mall/admin/customer-service/config.uvue delete mode 100644 pages/mall/admin/customer-service/list.uvue delete mode 100644 pages/mall/admin/customer-service/messages.uvue delete mode 100644 pages/mall/admin/customer-service/script.uvue create mode 100644 pages/mall/admin/decoration/category.uvue create mode 100644 pages/mall/admin/decoration/home.uvue create mode 100644 pages/mall/admin/decoration/user.uvue rename {docs/admin => pages/mall/admin/docs}/00_READ_ME_FIRST.md (100%) rename {docs/admin => pages/mall/admin/docs}/ADMIN_LAYOUT_GUIDE.md (100%) rename {docs/admin => pages/mall/admin/docs}/ADMIN_LAYOUT_IMPLEMENTATION_COMPLETE.md (100%) rename {docs/admin => pages/mall/admin/docs}/ADMIN_LAYOUT_PROGRESS_REPORT.md (100%) rename {docs/admin => pages/mall/admin/docs}/ADMIN_LAYOUT_TRANSFORMATION_100_COMPLETE.md (100%) rename {docs/admin => pages/mall/admin/docs}/ADMIN_LAYOUT_TRANSFORMATION_COMPLETE.md (100%) rename {docs => pages/mall/admin/docs}/ADMIN_MANAGEMENT_GUIDE.md (100%) rename {docs/admin => pages/mall/admin/docs}/ADMIN_PAGES_REFACTORING_PLAN.md (100%) rename {docs/admin => pages/mall/admin/docs}/ADMIN_PAGE_CHECKLIST.csv (100%) rename {docs/admin => pages/mall/admin/docs}/ADMIN_PAGE_COMPLETE.md (100%) rename {docs/admin => pages/mall/admin/docs}/ADMIN_PAGE_COMPLIANCE_CHECKLIST.md (100%) rename {docs/admin => pages/mall/admin/docs}/ADMIN_PAGE_INDEX.md (100%) rename {docs/admin => pages/mall/admin/docs}/ADMIN_PAGE_MODIFICATION_PLAN.md (100%) rename {docs/admin => pages/mall/admin/docs}/ADMIN_PAGE_QUICK_REFERENCE.md (100%) rename {docs/admin => pages/mall/admin/docs}/ADMIN_PAGE_START_HERE.md (100%) rename {docs/admin => pages/mall/admin/docs}/ADMIN_PAGE_SUMMARY.md (100%) rename {docs/admin => pages/mall/admin/docs}/ADMIN_PROJECT_FINAL_REPORT.md (100%) rename {docs/admin => pages/mall/admin/docs}/ADMIN_REFACTOR_INDEX.md (100%) rename {docs/admin => pages/mall/admin/docs}/ADMIN_REFACTOR_PROGRESS.md (100%) rename {docs/admin => pages/mall/admin/docs}/COMPONENT_SPECIFICATION.md (100%) rename {docs => pages/mall/admin/docs}/CRMEB_DASHBOARD_GUIDE.md (100%) rename {docs => pages/mall/admin/docs}/CRMEB_TO_UVUE_MIGRATION_GUIDE.md (100%) rename {docs/admin => pages/mall/admin/docs}/CRMEB_UVUE_MIGRATION_GUIDE.md (100%) rename {docs/admin => pages/mall/admin/docs}/DELIVERY_SUMMARY.md (100%) rename {docs/admin => pages/mall/admin/docs}/DESIGN_DECORATION_GUIDE.md (100%) rename {docs/admin => pages/mall/admin/docs}/DESIGN_IMPLEMENTATION_REPORT.md (100%) rename {docs/admin => pages/mall/admin/docs}/DESIGN_MODULE_UPGRADE_REPORT.md (100%) rename {docs/admin => pages/mall/admin/docs}/DESIGN_MODULE_USER_GUIDE.md (100%) rename {docs/admin => pages/mall/admin/docs}/DESIGN_QUICK_REFERENCE.md (100%) rename {docs/admin => pages/mall/admin/docs}/ENGINEERING_BEST_PRACTICES.md (100%) rename {docs => pages/mall/admin/docs}/FRONTEND_ARCHITECTURE_ANALYSIS.md (100%) rename {docs/admin => pages/mall/admin/docs}/IMPLEMENTATION_ROADMAP.md (100%) rename {docs/admin => pages/mall/admin/docs}/ORDER_MENU_HIGHLIGHT_COMPLETION_REPORT.md (100%) rename {docs/admin => pages/mall/admin/docs}/ORDER_MENU_HIGHLIGHT_FIX.md (100%) rename {docs/admin => pages/mall/admin/docs}/ORDER_MENU_HIGHLIGHT_QUICK_FIX.md (100%) rename {docs/admin => pages/mall/admin/docs}/PAGES_ROUTES.md (100%) rename {docs => pages/mall/admin/docs}/PAGE_STRUCTURE_ANALYSIS.md (100%) rename {docs/admin => pages/mall/admin/docs}/PAGE_STRUCTURE_SPECIFICATION.md (100%) rename {docs/admin => pages/mall/admin/docs}/PROJECT_COMPLETION_REPORT.md (100%) rename {docs/admin => pages/mall/admin/docs}/QUICK_REFERENCE.md (100%) rename {docs/admin => pages/mall/admin/docs}/QUICK_START_NEW_DEVELOPMENT.md (100%) rename {docs/admin => pages/mall/admin/docs}/README.md (100%) rename {docs/admin => pages/mall/admin/docs}/REFACTOR_BEFORE_AFTER.md (100%) rename {docs/admin => pages/mall/admin/docs}/REFACTOR_SUMMARY.md (100%) rename {docs/admin => pages/mall/admin/docs}/SERVICE_DELIVERY_CHECKLIST.md (100%) rename {docs/admin => pages/mall/admin/docs}/SERVICE_MODULE_IMPLEMENTATION.md (100%) rename {docs/admin => pages/mall/admin/docs}/SERVICE_PROJECT_SUMMARY.md (100%) rename {docs/admin => pages/mall/admin/docs}/SERVICE_QUICK_START.md (100%) rename {docs/admin => pages/mall/admin/docs}/STYLE_SPECIFICATION.md (100%) rename {docs/admin => pages/mall/admin/docs}/SYSTEM_INFO_FIX_GUIDE.md (100%) rename {docs/admin => pages/mall/admin/docs}/SYSTEM_INFO_ROOT_CAUSE.md (100%) rename {docs/admin => pages/mall/admin/docs}/SYSTEM_INFO_SIDEBAR_FIX.md (100%) rename {docs => pages/mall/admin/docs}/UNI_APP_X_PAGE_FIX_GUIDE.md (100%) create mode 100644 pages/mall/admin/finance/balance_record.uvue create mode 100644 pages/mall/admin/finance/balance_stats.uvue create mode 100644 pages/mall/admin/finance/bill.uvue create mode 100644 pages/mall/admin/finance/capital_flow.uvue create mode 100644 pages/mall/admin/finance/commission.uvue create mode 100644 pages/mall/admin/finance/finance-placeholder.scss create mode 100644 pages/mall/admin/finance/invoice.uvue create mode 100644 pages/mall/admin/finance/recharge.uvue create mode 100644 pages/mall/admin/finance/transaction_stats.uvue create mode 100644 pages/mall/admin/finance/withdrawal.uvue delete mode 100644 pages/mall/admin/homePage/index.uvue.bak create mode 100644 pages/mall/admin/kefu/config.uvue create mode 100644 pages/mall/admin/kefu/feedback.uvue create mode 100644 pages/mall/admin/kefu/list.uvue create mode 100644 pages/mall/admin/kefu/words.uvue create mode 100644 pages/mall/admin/maintain/dev/config.uvue create mode 100644 pages/mall/admin/marketing/coupon/user.uvue create mode 100644 pages/mall/admin/marketing/integral/statistic.uvue delete mode 100644 pages/mall/admin/product-statistics.uvue create mode 100644 pages/mall/admin/product/product-management/edit.uvue create mode 100644 pages/mall/admin/product/product-management/member-price.uvue create mode 100644 search_encoding.py diff --git a/docs/admin/ADMIN_MANAGEMENT_GUIDE.md b/docs/admin/ADMIN_MANAGEMENT_GUIDE.md deleted file mode 100644 index ccf25259..00000000 --- a/docs/admin/ADMIN_MANAGEMENT_GUIDE.md +++ /dev/null @@ -1,594 +0,0 @@ -# CRMEB管理端uvue实现操作指南 - -## 项目概述 - -本文档详细介绍基于CRMEB商城系统管理端功能,使用uvue + Supabase技术栈重新实现的完整管理后台操作指南。 - -## 技术架构 - -### 前端技术栈 -- **框架**: uvue (uni-app x) -- **状态管理**: Vue 3 Composition API -- **UI组件**: 自定义组件 + uni-app内置组件 -- **样式**: CSS + Flex布局 + 响应式设计 -- **设计风格**: 参考CRMEB开源商城系统,采用统一的卡片布局和配色方案 -- **图标库**: iconfont字体图标库 - -### 后端技术栈 -- **数据库**: Supabase (PostgreSQL) -- **API**: @components/supadb 组件库 -- **认证**: Supabase Auth -- **存储**: Supabase Storage -- **实时功能**: Supabase Realtime - -## 功能模块 - -### 1. 管理端首页 (`index.uvue`) - -#### 功能特性 -- **基础信息统计卡片**: 显示销售额、订单数、用户数等核心指标 -- **功能导航网格**: 快速访问各个管理模块 -- **数据可视化**: 实时统计数据展示 - -#### 页面结构 -参考CRMEB设计风格,采用统一的卡片布局和Flex布局: - -```vue - -``` - -#### 数据加载 -```typescript -// 获取基础统计数据 -const loadBaseStats = async () => { - const salesStats = await supa.rpc('get_sales_stats', { - start_date: yesterday, - end_date: today - }) - // 更新统计数据 -} -``` - -### 2. 用户管理 (`user-management.uvue`) - -#### 核心功能 -- **用户搜索筛选**: 支持多条件组合查询 -- **用户列表展示**: 分页显示用户信息 -- **批量操作**: 导出用户、群发消息、调整余额 -- **用户状态管理**: 启用/禁用用户账户 -- **用户详情**: 查看和编辑用户信息 - -#### 搜索功能 -```typescript -const searchTypes = ref([ - { value: 'all', label: '全部' }, - { value: 'uid', label: 'UID' }, - { value: 'phone', label: '手机号' }, - { value: 'nickname', label: '用户昵称' } -]) - -const userLevels = ref([]) // 用户等级选项 -const userGroups = ref([]) // 用户分组选项 -const agentLevels = ref([]) // 分销等级选项 -``` - -#### 用户操作 -```typescript -// 切换用户状态 -const toggleUserStatus = async (userId: number, currentStatus: number) => { - const newStatus = currentStatus === 1 ? 0 : 1 - await supa.from('users').update({ status: newStatus }).eq('id', userId) -} - -// 批量导出用户 -const exportUsers = () => { - // 导出逻辑 -} -``` - -### 3. 商品管理 (`product-management.uvue`) - -#### 功能特性 -- **商品列表**: 分页展示商品信息 -- **高级筛选**: 商品类型、分类、价格、库存等条件 -- **批量操作**: 批量上架/下架/删除 -- **商品状态管理**: 上架、下架、编辑 -- **商品规格**: 支持多规格商品管理 - -#### 商品筛选 -```typescript -const productTypes = ref([ - { value: '0', label: '普通商品' }, - { value: '1', label: '卡密商品' }, - { value: '2', label: '优惠券商品' }, - { value: '3', label: '虚拟商品' } -]) - -const deliveryTypes = ref([ - { value: '1', label: '快递配送' }, - { value: '2', label: '到店自提' } -]) -``` - -#### 商品操作 -```typescript -// 批量上架 -const batchOnShelf = async () => { - await supa.from('products') - .update({ is_show: true }) - .in('id', selectedProducts.value) -} - -// 删除商品 -const deleteProduct = async (productId: number) => { - await supa.from('products') - .update({ is_del: true }) - .eq('id', productId) -} -``` - -### 4. 订单管理 (`order-management.uvue`) - -#### 核心功能 -- **订单类型标签页**: 全部订单、普通订单、待支付、待发货等 -- **订单搜索**: 订单号、用户名、收货人等条件 -- **订单状态管理**: 确认订单、发货、查看物流 -- **订单详情**: 完整的订单信息展示 -- **批量操作**: 批量发货、导出订单 - -#### 订单状态 -```typescript -const orderStatuses = ref([ - { value: '0', label: '待确认' }, - { value: '1', label: '待支付' }, - { value: '2', label: '待发货' }, - { value: '3', label: '已发货' }, - { value: '4', label: '已完成' }, - { value: '5', label: '已取消' }, - { value: '6', label: '退款中' } -]) -``` - -#### 订单操作 -```typescript -// 确认订单 -const confirmOrder = async (orderId: number) => { - await supa.from('orders').update({ status: 1 }).eq('id', orderId) -} - -// 订单发货 -const confirmShip = async () => { - await supa.from('orders').update({ - status: 3, - ship_info: { - express_company: shipForm.express_company, - express_number: shipForm.express_number, - ship_time: new Date().toISOString() - } - }).eq('id', shipForm.order_id) -} -``` - -### 5. 财务管理 (`finance-management.uvue`) - -#### 功能模块 -- **财务概览**: 收入统计、账户余额、待结算金额 -- **财务明细**: 交易记录查询和筛选 -- **交易类型**: 订单收入、退款支出、提现支出等 -- **数据导出**: 支持导出财务报表 - -#### 财务统计 -```typescript -const overview = ref({ - today_income: '0.00', - month_income: '0.00', - account_balance: '0.00', - pending_settlement: '0.00' -}) -``` - -#### 交易记录查询 -```typescript -const loadRecords = async () => { - let query = supa.from('finance_records') - .select('*') - .order('created_at', { ascending: false }) - - // 筛选条件 - if (selectedType.value) { - query = query.eq('type', selectedType.value) - } - - // 分页 - const { data, count } = await query.range(from, to) -} -``` - -### 6. 系统设置 (`system-settings.uvue`) - -#### 设置分类 -- **基础设置**: 网站名称、域名、Logo、客服电话等 -- **支付设置**: 微信支付、支付宝、余额支付配置 -- **物流设置**: 默认物流公司、运费计算方式 -- **消息设置**: 短信、邮件通知配置 - -#### 设置保存 -```typescript -const saveSettings = async () => { - await supa.from('system_settings').upsert(settings.value) -} -``` - -## 组件架构 - -### 公共组件 -- **搜索表单**: 统一的搜索和筛选组件 -- **数据表格**: 列表展示和操作组件 -- **分页组件**: 统一的翻页功能 -- **弹窗组件**: 确认对话框和表单弹窗 - -### 样式规范 -参考CRMEB设计风格,采用统一的布局和配色: - -```css -/* 布局类 */ -.acea-row { - display: flex; - flex-direction: row; -} - -.row-between-wrapper { - justify-content: space-between; - align-items: center; -} - -/* 颜色规范 */ -.primary-theme: #fba02a; /* 橙色主题色 */ -.secondary-theme: #2291f8; /* 蓝色辅助色 */ -.success-color: #1abb1d; /* 成功色 */ -.danger-color: #ff6969; /* 危险色 */ - -/* 卡片样式 */ -.public-wrapper { - width: 690rpx; - background-color: #fff; - border-radius: 10rpx; - margin: 20rpx auto 0 auto; - padding: 30rpx; - box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1); -} - -/* 字体图标 */ -.iconfont { - font-family: 'iconfont'; - color: #2291f8; - font-size: 36rpx; - margin-right: 13rpx; - vertical-align: middle; -} -``` - -## 数据交互 - -### Supabase集成 -```typescript -import supa from '@/components/supadb/aksupainstance.uts' - -// 查询数据 -const { data, error } = await supa - .from('table_name') - .select('*') - .eq('field', value) - -// 插入数据 -const { data, error } = await supa - .from('table_name') - .insert(newData) - -// 更新数据 -const { data, error } = await supa - .from('table_name') - .update(updateData) - .eq('id', id) - -// 删除数据 -const { data, error } = await supa - .from('table_name') - .delete() - .eq('id', id) -``` - -### RPC调用 -```typescript -// 调用存储过程 -const { data, error } = await supa.rpc('function_name', { - param1: value1, - param2: value2 -}) -``` - -## 权限管理 - -### 基于角色的访问控制 -```typescript -// 权限检查 -const hasPermission = (permission: string) => { - // 检查用户权限逻辑 - return userPermissions.includes(permission) -} - -// 页面级权限控制 -onMounted(() => { - if (!hasPermission('admin.user.view')) { - uni.showToast({ - title: '无权限访问', - icon: 'error' - }) - uni.navigateBack() - } -}) -``` - -## 性能优化 - -### 1. 数据分页 -```typescript -const loadData = async (page: number = 1) => { - const pageSize = 20 - const from = (page - 1) * pageSize - const to = from + pageSize - 1 - - const { data } = await supa - .from('table') - .select('*') - .range(from, to) -} -``` - -### 2. 条件查询优化 -```typescript -// 使用索引字段进行查询 -const { data } = await supa - .from('orders') - .select('*') - .eq('status', 1) // 状态字段通常有索引 - .gte('created_at', startDate) - .order('created_at', { ascending: false }) -``` - -### 3. 实时数据订阅 -```typescript -// 监听数据变化 -const subscription = supa - .channel('table-changes') - .on('postgres_changes', { - event: '*', - schema: 'public', - table: 'orders' - }, (payload) => { - // 处理数据变化 - updateLocalData(payload) - }) - .subscribe() -``` - -## 错误处理 - -### 统一错误处理 -```typescript -const handleError = (error: any) => { - console.error('操作失败:', error) - - let message = '操作失败,请重试' - if (error.message) { - message = error.message - } - - uni.showToast({ - title: message, - icon: 'error' - }) -} -``` - -### 网络请求错误 -```typescript -try { - const { data, error } = await supa.from('table').select('*') - if (error) throw error - // 处理成功的数据 -} catch (error) { - handleError(error) -} -``` - -## 响应式设计 - -### 移动端适配 -```scss -// 响应式断点 -@media (max-width: 750rpx) { - .container { - padding: 20rpx; - } - - .grid { - grid-template-columns: 1fr; - gap: 15rpx; - } - - .table-row { - flex-wrap: wrap; - - .table-cell { - min-width: 200rpx; - margin-bottom: 10rpx; - } - } -} -``` - -## 部署和维护 - -### 环境配置 -```javascript -// config/admin.js -export default { - supabase: { - url: process.env.SUPABASE_URL, - anonKey: process.env.SUPABASE_ANON_KEY, - serviceRoleKey: process.env.SUPABASE_SERVICE_ROLE_KEY - }, - pagination: { - defaultPageSize: 20, - maxPageSize: 100 - }, - upload: { - maxFileSize: 10 * 1024 * 1024, // 10MB - allowedTypes: ['image/jpeg', 'image/png', 'image/webp'] - } -} -``` - -### 日志记录 -```typescript -// 操作日志记录 -const logOperation = async (action: string, details: any) => { - await supa.from('admin_logs').insert({ - admin_id: currentAdmin.id, - action, - details, - ip: getClientIP(), - user_agent: navigator.userAgent, - created_at: new Date().toISOString() - }) -} -``` - -## 开发规范 - -### 代码组织 -``` -pages/mall/admin/ -├── index.uvue # 管理首页 -├── user-management.uvue # 用户管理 -├── product-management.uvue # 商品管理 -├── order-management.uvue # 订单管理 -├── finance-management.uvue # 财务管理 -├── system-settings.uvue # 系统设置 -└── components/ # 公共组件 - ├── SearchForm.uvue - ├── DataTable.uvue - ├── Pagination.uvue - └── Modal.uvue -``` - -### 命名规范 -- **文件命名**: 使用 kebab-case (user-management.uvue) -- **变量命名**: 使用 camelCase (userList, isLoading) -- **组件命名**: 使用 PascalCase (UserManagement) -- **函数命名**: 使用 camelCase (loadUserList, handleSubmit) - -### 注释规范 -```typescript -/** - * 用户管理页面 - * 功能:用户列表展示、搜索筛选、状态管理等 - */ - -// 函数注释 -/** - * 加载用户列表 - * @param page 页码 - * @param filters 筛选条件 - */ -const loadUserList = async (page: number = 1, filters: any = {}) => { - // 具体实现 -} -``` - -## 常见问题 - -### 1. 数据加载慢 -**问题**: 列表数据加载缓慢 -**解决方案**: -- 添加合适的数据库索引 -- 实现数据分页 -- 使用缓存机制 -- 优化查询条件 - -### 2. 权限控制 -**问题**: 用户权限判断不准确 -**解决方案**: -- 在路由层面进行权限检查 -- 实现基于角色的访问控制 -- 前端页面级权限验证 - -### 3. 实时数据同步 -**问题**: 多用户同时操作数据冲突 -**解决方案**: -- 使用 Supabase 实时订阅 -- 实现乐观更新 -- 添加数据版本控制 - -## 更新日志 - -### v1.0.0 (2024-01-22) -- ✅ 完成基础管理功能实现 -- ✅ 用户管理模块 -- ✅ 商品管理模块 -- ✅ 订单管理模块 -- ✅ 财务管理模块 -- ✅ 系统设置模块 - -### 计划功能 -- 🔄 营销管理模块 -- 🔄 数据统计图表 -- 🔄 批量操作优化 -- 🔄 移动端适配完善 -- 🔄 性能优化 - ---- - -本文档持续更新中,如有问题请及时反馈。 \ No newline at end of file diff --git a/docs/admin/CRMEB_DASHBOARD_GUIDE.md b/docs/admin/CRMEB_DASHBOARD_GUIDE.md deleted file mode 100644 index 3379830a..00000000 --- a/docs/admin/CRMEB_DASHBOARD_GUIDE.md +++ /dev/null @@ -1,475 +0,0 @@ -# CRMEB 标准版后台 - 数据看板与用户统计页 - -## 📋 项目概述 - -基于 uni-app-x 自主开发的 CRMEB 风格后台管理系统,包含完整的数据看板和用户统计功能。严格遵循 CRMEB 的设计规范和布局结构,所有代码完全自主编写。 - -## 🗂️ 目录结构 - -``` -mall/ -├── layouts/ -│ └── admin/ -│ ├── index.uvue # 主布局组件 -│ ├── components/ -│ │ └── card.uvue # 卡片组件 -│ └── utils/ -│ └── echarts-config.uts # 图表配置 -├── pages/ -│ ├── minimal.uvue # 测试页面 -│ └── mall/ -│ └── admin/ -│ ├── index.uvue # 管理后台首页(数据看板) -│ ├── user-management.uvue # 用户管理 -│ ├── product-management.uvue # 商品管理 -│ ├── order-management.uvue # 订单管理 -│ ├── finance-management.uvue # 财务管理 -│ ├── user-statistics.uvue # 用户统计页 -│ └── system-settings.uvue # 系统设置 -└── pages.json # 页面配置 -``` - -## 🎨 设计规范 - -### 布局结构 -- **24栅格系统**: 所有元素对齐,统一间距 -- **白色背景**: 主背景色 #f0f2f5 -- **卡片设计**: 轻阴影 + 圆角 + 边框 -- **响应式**: >=1200px 四卡一行;<=1200px 两卡一行;<=768px 单列 - -### 配色方案 -```scss -// 主色调 -$primary-color: #1890ff; -$success-color: #52c41a; -$warning-color: #faad14; -$danger-color: #f5222d; - -// 中性色 -$text-primary: #262626; -$text-secondary: #666; -$text-disabled: #999; -$border-color: #e8e8e8; -$background: #fff; -$page-background: #f0f2f5; -``` - -## 🏗️ 组件架构 - -### AdminLayout 主布局 - -#### 功能特性 -- **左侧侧边栏**: 深色背景,一级菜单 + 折叠功能 -- **顶部导航**: 面包屑 + 工具图标 + 用户信息 -- **多标签页**: 可关闭的页面标签 -- **页面容器**: 带滚动条的主内容区域 - -#### 技术实现 -```vue - -``` - -### Card 卡片组件 - -#### API 接口 -```typescript -interface CardProps { - title?: string - bordered?: boolean - shadow?: string - bodyStyle?: Record -} -``` - -#### 使用示例 -```vue - - 卡片内容 - -``` - -## 📊 页面功能详解 - -### 1. 数据看板 (Dashboard) - -#### 第一行:KPI 指标卡片 -```vue - - - - - 销售额 - 今日 - - - ¥125,680.50 - - 5.7% - - - - 昨日:¥118,920.30 - 本月累计:¥2,857,808.90 - - - - -``` - -**数据结构**: -```typescript -interface KPIData { - today: number - yesterday: number - monthTotal: number - change: number // 环比百分比 -} -``` - -#### 第二行:订单统计图表 -```vue - - - - - - - - -``` - -#### 第三行:用户分析图表 -```vue - - - - - - - - - - - -``` - -### 2. 用户统计页 - -#### 筛选条件栏 -```vue - - - - - 用户渠道: - - - - - - 时间范围: - - - - - - - - - - - - - - -``` - -#### 指标概览卡片 -```vue - - - - - - - - {{ metric.title }} - {{ formatNumber(metric.value) }} - - {{ metric.change }}% - 较上月 - - - - -``` - -#### 多折线趋势图 -```vue - - - - - - - {{ item.name }} - - - - - - - - - -``` - -## 🔧 ECharts 图表配置 - -### 组合图表配置 -```javascript -export const getOrderChartOption = (period) => ({ - title: { text: `订单统计 (${period})`, left: 'center' }, - tooltip: { trigger: 'axis' }, - legend: { data: ['订单金额', '订单数量'] }, - xAxis: { type: 'category', data: dateLabels }, - yAxis: [ - { type: 'value', name: '订单金额' }, - { type: 'value', name: '订单数量' } - ], - series: [ - { - name: '订单金额', - type: 'bar', - data: amountData, - itemStyle: { color: '#1890ff' } - }, - { - name: '订单数量', - type: 'line', - yAxisIndex: 1, - data: countData, - itemStyle: { color: '#52c41a' } - } - ] -}) -``` - -### 多折线图配置 -```javascript -export const getUserStatisticsOption = () => ({ - title: { text: '用户数据趋势分析' }, - tooltip: { trigger: 'axis' }, - legend: { - data: ['新增用户', '访客数', '浏览量', '成交用户', '付费会员'] - }, - series: [ - { name: '新增用户', type: 'line', data: newUsersData }, - { name: '访客数', type: 'line', data: visitorsData }, - { name: '浏览量', type: 'line', data: pageViewsData }, - { name: '成交用户', type: 'line', data: conversionsData }, - { name: '付费会员', type: 'line', data: vipUsersData } - ] -}) -``` - -## 📱 响应式设计 - -### 断点定义 -```scss -// 大屏:4卡片一行 -@media screen and (min-width: 1200px) { - .kpi-row { /* 4列布局 */ } -} - -// 中屏:2卡片一行 -@media screen and (max-width: 1200px) { - .kpi-row { /* 2列布局 */ } -} - -// 小屏:单列布局 -@media screen and (max-width: 768px) { - .kpi-row { flex-direction: column; } - .chart-row.two-cols { flex-direction: column; } -} -``` - -## 🚀 功能特性 - -### ✅ 已实现功能 -- [x] CRMEB 风格垂直菜单布局 -- [x] 响应式 24 栅格系统 -- [x] KPI 指标卡片展示 -- [x] 订单统计组合图表 -- [x] 用户趋势分析图表 -- [x] 用户构成饼图 -- [x] 用户统计筛选功能 -- [x] 多折线趋势图表 -- [x] 完整的菜单导航 -- [x] 标签页管理 -- [x] 返回顶部功能 - -### 🔄 可扩展功能 -- [ ] ECharts 实际集成 -- [ ] 数据实时更新 -- [ ] 图表交互功能 -- [ ] 数据导出功能 -- [ ] 更多图表类型 - -## 📋 使用指南 - -### 1. 页面访问 -```javascript -// 主页面访问 -/pages/mall/admin/index // 数据看板 -/pages/mall/admin/user-statistics // 用户统计页 - -// 菜单导航 -uni.navigateTo({ - url: '/pages/mall/admin/user-statistics' -}) -``` - -### 2. 数据更新 -```javascript -// KPI 数据更新 -const salesData = ref({ - today: 125680.50, - yesterday: 118920.30, - monthTotal: 2857808.90, - change: 5.7 -}) -``` - -### 3. 图表配置 -```javascript -import { getOrderChartOption } from '@/layouts/admin/utils/echarts-config' - -// 使用配置 -const option = getOrderChartOption('30days') -``` - -## 🎨 样式规范 - -### 卡片样式 -```scss -.admin-card { - background: #fff; - border-radius: 8rpx; - box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06); - border: 1rpx solid #e8e8e8; - - &.shadow-small { box-shadow: 0 1rpx 3rpx rgba(0, 0, 0, 0.04); } - &.shadow-large { box-shadow: 0 6rpx 16rpx rgba(0, 0, 0, 0.12); } -} -``` - -### 按钮样式 -```scss -.btn-primary { - background: #1890ff; - color: #fff; - border-radius: 6rpx; - padding: 12rpx 24rpx; -} - -.btn-secondary { - background: #fff; - color: #666; - border: 1rpx solid #d9d9d9; -} -``` - -## 📚 技术栈 - -- **框架**: uni-app-x + Vue 3 -- **语言**: TypeScript + uvue -- **样式**: SCSS -- **图表**: ECharts (配置化) -- **布局**: 24栅格系统 -- **响应式**: 移动端适配 - -## 🔧 开发规范 - -### 命名规范 -- **组件**: PascalCase (`AdminLayout.vue`) -- **文件**: kebab-case (`user-statistics.uvue`) -- **变量**: camelCase (`salesData`) -- **常量**: UPPER_SNAKE_CASE (`API_BASE_URL`) - -### 代码组织 -```vue - - - - - -``` - -## 🎯 项目成果 - -✅ **完全自主开发**: 无任何源码复制,100%自主编写 -✅ **CRMEB 风格**: 严格遵循设计规范和布局结构 -✅ **完整功能**: 数据看板 + 用户统计双页面 -✅ **响应式设计**: 桌面/平板/手机全适配 -✅ **技术先进**: Vue 3 + TypeScript + 组合式API -✅ **可维护性**: 模块化架构,易于扩展 - ---- - -## 🚀 部署运行 - -```bash -# 开发环境 -npm run dev:h5 - -# 构建生产 -npm run build:h5 - -# 运行到小程序 -npm run dev:mp-weixin -``` - -访问地址:`http://localhost:5173/pages/mall/admin/index` - ---- - -*本项目完全自主开发,实现了CRMEB标准版后台的核心功能,为后续功能扩展奠定了坚实基础。* \ No newline at end of file diff --git a/docs/admin/CRMEB_TO_UVUE_MIGRATION_GUIDE.md b/docs/admin/CRMEB_TO_UVUE_MIGRATION_GUIDE.md deleted file mode 100644 index 7d4d0909..00000000 --- a/docs/admin/CRMEB_TO_UVUE_MIGRATION_GUIDE.md +++ /dev/null @@ -1,807 +0,0 @@ -# CRMEB商城系统到uvue项目的重构迁移指南 - -## 项目概述 - -本文档基于CRMEB开源商城系统(PHP版本),指导如何将其核心功能迁移到基于uvue技术栈的项目中。后端使用`@components/supadb`组件库实现,不使用PHP技术栈。 - -## 参考项目分析 - -### CRMEB核心功能模块 - -#### 1. 用户系统 (User Module) -- **用户注册登录**:手机号验证码、微信授权登录 -- **用户资料管理**:个人信息、收货地址、会员等级 -- **用户积分系统**:积分获取、积分消费记录 -- **分销系统**:用户推广、佣金结算 - -#### 2. 商品系统 (Product Module) -- **商品管理**:商品信息、SKU规格、商品分类 -- **商品展示**:商品详情、商品列表、商品搜索 -- **库存管理**:商品库存、规格库存管理 - -#### 3. 订单系统 (Order Module) -- **购物车**:添加商品、修改数量、删除商品 -- **订单创建**:订单确认、地址选择、支付方式 -- **订单管理**:订单状态跟踪、订单取消、退款处理 -- **物流跟踪**:快递信息查询、物流状态更新 - -#### 4. 营销活动 (Activity Module) -- **秒杀活动**:限时抢购、库存锁定 -- **拼团活动**:团购发起、参团流程 -- **砍价活动**:好友助力、砍价进度 -- **优惠券系统**:券领取、使用规则 -- **积分商城**:积分兑换商品 - -#### 5. 支付系统 (Payment Module) -- **多渠道支付**:微信支付、支付宝、余额支付 -- **支付回调**:订单状态更新、支付记录 - -#### 6. 客服系统 (Service Module) -- **在线客服**:实时聊天、消息记录 -- **售后服务**:退换货处理、服务评价 - -#### 7. 内容管理系统 (CMS Module) -- **文章系统**:资讯发布、分类管理 -- **广告位管理**:首页banner、推荐位 - -#### 8. 系统配置 (System Module) -- **基础配置**:站点信息、支付配置、物流配置 -- **权限管理**:管理员权限、操作日志 - -## 技术栈对比 - -### 原CRMEB技术栈 -``` -后端: ThinkPHP 6 + MySQL + Redis -前端: Vue2 + ElementUI + UniApp -其他: Workerman(长连接)、队列、定时任务 -``` - -### 目标技术栈 -``` -后端: Supabase (PostgreSQL + Auth + Storage + Edge Functions) -前端: uvue + @components/supadb -其他: 实时订阅、文件存储、服务器less函数 -``` - -## 数据架构设计 - -### Supabase数据库表结构设计 - -#### 核心数据表 - -##### 1. 用户表 (users) -```sql --- 继承Supabase auth.users表,扩展字段 -CREATE TABLE public.users ( - id UUID REFERENCES auth.users(id) PRIMARY KEY, - phone TEXT, - nickname TEXT, - avatar_url TEXT, - gender INTEGER DEFAULT 0, - birthday DATE, - level_id INTEGER DEFAULT 0, - integral INTEGER DEFAULT 0, - balance DECIMAL(10,2) DEFAULT 0, - spread_uid INTEGER, - spread_time TIMESTAMP WITH TIME ZONE, - created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), - updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() -); -``` - -##### 2. 商品表 (products) -```sql -CREATE TABLE public.products ( - id SERIAL PRIMARY KEY, - title TEXT NOT NULL, - description TEXT, - images TEXT[], - category_id INTEGER, - brand_id INTEGER, - price DECIMAL(10,2), - ot_price DECIMAL(10,2), - cost DECIMAL(10,2), - stock INTEGER DEFAULT 0, - sales INTEGER DEFAULT 0, - is_show BOOLEAN DEFAULT true, - is_del BOOLEAN DEFAULT false, - created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), - updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() -); -``` - -##### 3. 商品规格表 (product_skus) -```sql -CREATE TABLE public.product_skus ( - id SERIAL PRIMARY KEY, - product_id INTEGER REFERENCES products(id), - sku TEXT, - price DECIMAL(10,2), - stock INTEGER DEFAULT 0, - image TEXT, - attributes JSONB, - created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() -); -``` - -##### 4. 订单表 (orders) -```sql -CREATE TABLE public.orders ( - id SERIAL PRIMARY KEY, - order_sn TEXT UNIQUE, - user_id UUID REFERENCES users(id), - total_price DECIMAL(10,2), - pay_price DECIMAL(10,2), - coupon_price DECIMAL(10,2), - pay_type INTEGER DEFAULT 1, -- 1微信 2余额 3线下 - status INTEGER DEFAULT 0, -- 订单状态 - address_info JSONB, - mark TEXT, - paid BOOLEAN DEFAULT false, - pay_time TIMESTAMP WITH TIME ZONE, - created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), - updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() -); -``` - -##### 5. 订单商品表 (order_items) -```sql -CREATE TABLE public.order_items ( - id SERIAL PRIMARY KEY, - order_id INTEGER REFERENCES orders(id), - product_id INTEGER REFERENCES products(id), - sku_id INTEGER REFERENCES product_skus(id), - product_title TEXT, - product_image TEXT, - sku_info JSONB, - price DECIMAL(10,2), - quantity INTEGER, - total_price DECIMAL(10,2), - created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() -); -``` - -##### 6. 购物车表 (cart) -```sql -CREATE TABLE public.cart ( - id SERIAL PRIMARY KEY, - user_id UUID REFERENCES users(id), - product_id INTEGER REFERENCES products(id), - sku_id INTEGER REFERENCES product_skus(id), - quantity INTEGER, - selected BOOLEAN DEFAULT true, - created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), - updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() -); -``` - -##### 7. 优惠券表 (coupons) -```sql -CREATE TABLE public.coupons ( - id SERIAL PRIMARY KEY, - title TEXT, - type INTEGER, -- 1满减 2折扣 - value DECIMAL(10,2), - min_price DECIMAL(10,2), - use_start_time TIMESTAMP WITH TIME ZONE, - use_end_time TIMESTAMP WITH TIME ZONE, - stock INTEGER, - receive_count INTEGER DEFAULT 0, - is_show BOOLEAN DEFAULT true, - created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() -); -``` - -##### 8. 用户优惠券表 (user_coupons) -```sql -CREATE TABLE public.user_coupons ( - id SERIAL PRIMARY KEY, - user_id UUID REFERENCES users(id), - coupon_id INTEGER REFERENCES coupons(id), - status INTEGER DEFAULT 0, -- 0未使用 1已使用 2已过期 - use_time TIMESTAMP WITH TIME ZONE, - created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() -); -``` - -## API接口设计 - -### 使用@components/supadb实现的数据操作 - -#### 用户相关接口 - -##### 用户注册 -```typescript -// 使用Supabase Auth实现 -const { data, error } = await supa.auth.signUp({ - email: 'user@example.com', - password: 'password' -}) -``` - -##### 用户登录 -```typescript -const { data, error } = await supa.auth.signInWithPassword({ - email: 'user@example.com', - password: 'password' -}) -``` - -##### 获取用户信息 -```typescript -// 使用supadb组件 - - - -``` - -##### 更新用户信息 -```typescript -const result = await supa.from('users').update(userData).eq('id', userId) -``` - -#### 商品相关接口 - -##### 获取商品列表 -```vue - - - - - - -``` - -##### 获取商品详情 -```vue - - - -``` - -##### 商品搜索 -```vue - - - -``` - -#### 订单相关接口 - -##### 创建订单 -```typescript -// 先创建订单记录 -const orderData = { - order_sn: generateOrderSn(), - user_id: userId, - total_price: totalPrice, - // ...其他字段 -} -const { data: order } = await supa.from('orders').insert(orderData).select().single() - -// 然后创建订单商品记录 -const orderItems = cartItems.map(item => ({ - order_id: order.id, - product_id: item.product_id, - // ...其他字段 -})) -await supa.from('order_items').insert(orderItems) -``` - -##### 获取订单列表 -```vue - - - - - -``` - -#### 营销活动接口 - -##### 秒杀活动 -```vue - - - -``` - -##### 优惠券领取 -```typescript -// 检查用户是否已领取 -const { data: existing } = await supa - .from('user_coupons') - .select('*') - .eq('user_id', userId) - .eq('coupon_id', couponId) - .single() - -if (!existing) { - await supa.from('user_coupons').insert({ - user_id: userId, - coupon_id: couponId - }) -} -``` - -## uvue前端页面重构方案 - -### 页面结构重组 - -#### 1. 首页 (pages/index/index.uvue) -```vue - - - -``` - -#### 2. 商品详情页 (pages/goods/detail.uvue) -```vue - - - -``` - -#### 3. 购物车页面 (pages/cart/index.uvue) -```vue - - - -``` - -## 实时功能实现 - -### 使用Supabase实时订阅 - -#### 订单状态更新监听 -```typescript -// 监听订单状态变化 -const orderSubscription = supa - .channel('order-updates') - .on('postgres_changes', - { - event: 'UPDATE', - schema: 'public', - table: 'orders', - filter: `user_id=eq.${userId}` - }, - (payload) => { - console.log('Order updated:', payload) - // 更新订单状态 - } - ) - .subscribe() -``` - -#### 库存变化监听 -```typescript -// 监听商品库存变化 -const stockSubscription = supa - .channel('stock-updates') - .on('postgres_changes', - { - event: 'UPDATE', - schema: 'public', - table: 'products' - }, - (payload) => { - // 更新本地商品库存 - updateLocalStock(payload.new) - } - ) - .subscribe() -``` - -## 文件存储实现 - -### 使用Supabase Storage - -#### 商品图片上传 -```typescript -const uploadProductImage = async (filePath: string, productId: number) => { - const fileName = `product_${productId}_${Date.now()}.jpg` - const { data, error } = await supa.storage - .from('products') - .upload(fileName, filePath) - - if (data) { - const { data: urlData } = supa.storage - .from('products') - .getPublicUrl(fileName) - - return urlData.publicUrl - } -} -``` - -#### 用户头像上传 -```typescript -const uploadAvatar = async (filePath: string) => { - const fileName = `avatar_${userId}_${Date.now()}.jpg` - const { data, error } = await supa.storage - .from('avatars') - .upload(fileName, filePath) - - if (data) { - const { data: urlData } = supa.storage - .from('avatars') - .getPublicUrl(fileName) - - // 更新用户头像 - await supa.from('users').update({ - avatar_url: urlData.publicUrl - }).eq('id', userId) - } -} -``` - -## 服务器端逻辑实现 - -### 使用Supabase Edge Functions - -#### 订单创建函数 -```typescript -// supabase/functions/create-order/index.ts -import { serve } from "https://deno.land/std@0.168.0/http/server.ts" -import { createClient } from 'https://esm.sh/@supabase/supabase-js@2' - -serve(async (req) => { - const { userId, items, address } = await req.json() - - const supabase = createClient( - Deno.env.get('SUPABASE_URL') ?? '', - Deno.env.get('SUPABASE_ANON_KEY') ?? '' - ) - - // 生成订单号 - const orderSn = `ORDER${Date.now()}${Math.random().toString(36).substr(2, 6).toUpperCase()}` - - // 计算总价 - let totalPrice = 0 - for (const item of items) { - const { data: product } = await supabase - .from('products') - .select('price') - .eq('id', item.productId) - .single() - - totalPrice += product.price * item.quantity - } - - // 创建订单 - const { data: order, error } = await supabase - .from('orders') - .insert({ - order_sn: orderSn, - user_id: userId, - total_price: totalPrice, - address_info: address - }) - .select() - .single() - - if (error) throw error - - // 创建订单商品记录 - const orderItems = items.map(item => ({ - order_id: order.id, - product_id: item.productId, - quantity: item.quantity, - price: item.price, - total_price: item.price * item.quantity - })) - - const { error: itemsError } = await supabase - .from('order_items') - .insert(orderItems) - - if (itemsError) throw itemsError - - return new Response( - JSON.stringify({ order }), - { headers: { "Content-Type": "application/json" } } - ) -}) -``` - -#### 支付回调函数 -```typescript -// supabase/functions/payment-callback/index.ts -import { serve } from "https://deno.land/std@0.168.0/http/server.ts" -import { createClient } from 'https://esm.sh/@supabase/supabase-js@2' - -serve(async (req) => { - const { orderSn, paymentResult } = await req.json() - - const supabase = createClient( - Deno.env.get('SUPABASE_URL') ?? '', - Deno.env.get('SUPABASE_ANON_KEY') ?? '' - ) - - // 更新订单支付状态 - const { error } = await supabase - .from('orders') - .update({ - paid: true, - pay_time: new Date().toISOString(), - status: 1 // 已支付 - }) - .eq('order_sn', orderSn) - - if (error) throw error - - return new Response( - JSON.stringify({ success: true }), - { headers: { "Content-Type": "application/json" } } - ) -}) -``` - -## 组件重构对照表 - -### CRMEB组件 → uvue组件映射 - -| CRMEB组件 | uvue组件 | 功能说明 | -|----------|---------|---------| -| HomeComb | home-comb.uvue | 首页搜索组合 | -| GoodList | product-list.uvue | 商品列表 | -| CouponWindow | coupon-popup.uvue | 优惠券弹窗 | -| CartList | cart-list.uvue | 购物车列表 | -| Payment | payment-selector.uvue | 支付方式选择 | -| AddressWindow | address-selector.uvue | 地址选择弹窗 | -| UserEvaluation | product-review.uvue | 商品评价 | -| ShareRedPackets | share-popup.uvue | 分享红包 | - -## 性能优化建议 - -### 1. 数据缓存策略 -```typescript -// 使用Supabase内置缓存 -const { data, error } = await supa - .from('products') - .select('*') - .eq('category_id', categoryId) - .order('sales', { ascending: false }) - .limit(20) - // 启用缓存 - .single() -``` - -### 2. 图片懒加载 -```vue - -``` - -### 3. 列表虚拟化 -```vue - -``` - -## 部署和维护 - -### 环境配置 -```javascript -// config/app.js -export default { - supabase: { - url: 'https://your-project.supabase.co', - anonKey: 'your-anon-key', - serviceRoleKey: 'your-service-role-key' // 服务端使用 - } -} -``` - -### 数据库迁移 -```sql --- 数据库初始化脚本 --- 创建表结构 --- 设置RLS策略 --- 创建索引 --- 设置触发器 -``` - -### 监控和日志 -```typescript -// 错误监控 -const handleError = (error) => { - console.error('App Error:', error) - // 上报到监控系统 -} - -// 性能监控 -const reportPerformance = (metrics) => { - // 上报性能数据 -} -``` - -## 总结 - -通过本重构指南,我们将CRMEB的核心功能成功迁移到基于uvue + Supabase的技术栈: - -1. **数据层**:使用Supabase替代MySQL + Redis -2. **API层**:使用@components/supadb替代ThinkPHP -3. **前端**:使用uvue替代uni-app -4. **实时功能**:使用Supabase实时订阅 -5. **文件存储**:使用Supabase Storage -6. **服务器逻辑**:使用Edge Functions - -这种架构具有以下优势: -- **开发效率高**:减少后端开发工作 -- **维护成本低**:Serverless架构 -- **扩展性好**:支持实时功能和全球化部署 -- **安全性高**:Supabase提供完善的安全机制 - -实际迁移时需要根据具体业务需求进行调整,并充分测试各项功能。 \ No newline at end of file diff --git a/docs/admin/FRONTEND_ARCHITECTURE_ANALYSIS.md b/docs/admin/FRONTEND_ARCHITECTURE_ANALYSIS.md deleted file mode 100644 index 1e8000a5..00000000 --- a/docs/admin/FRONTEND_ARCHITECTURE_ANALYSIS.md +++ /dev/null @@ -1,427 +0,0 @@ -# CRMEB Admin 前端架构梳理分析 - -## 项目概述 -- **项目名称**: CRMEB Admin Template -- **技术栈**: Vue.js + Element UI + Vue Router + Vuex -- **项目类型**: 电商管理后台系统 -- **分析时间**: 2026-01-23 - -## 1. 页面总览表 - -| 路由路径 | 页面标题 | 所属端 | 是否tab/子包 | 说明 | 入口文件 | -|---------|---------|-------|-------------|------|---------| -| `/admin/index` | 主页 | Admin后台 | 否 | 系统首页,包含基础统计信息 | `src/pages/index/index.vue` | -| `/admin/product/product_list` | 商品管理 | Admin后台 | 否 | 商品列表管理页面 | `src/pages/product/productList/index.vue` | -| `/admin/product/product_classify` | 商品分类 | Admin后台 | 否 | 商品分类管理 | `src/pages/product/productClassify/index.vue` | -| `/admin/product/add_product/:id?` | 商品添加 | Admin后台 | 否 | 添加/编辑商品 | `src/pages/product/productAdd/index.vue` | -| `/admin/order/list` | 订单管理 | Admin后台 | 否 | 订单列表管理 | `src/pages/order/orderList/index.vue` | -| `/admin/order/offline` | 收银订单 | Admin后台 | 否 | 线下收银订单 | `src/pages/order/offline/index.vue` | -| `/admin/order/refund` | 售后订单 | Admin后台 | 否 | 售后退款订单 | `src/pages/order/refund/index.vue` | -| `/admin/user/list` | 用户管理 | Admin后台 | 否 | 用户列表管理 | `src/pages/user/list/index.vue` | -| `/admin/user/level` | 用户等级 | Admin后台 | 否 | 用户等级管理 | `src/pages/user/level/index.vue` | -| `/admin/user/group` | 用户分组 | Admin后台 | 否 | 用户分组管理 | `src/pages/user/group/index.vue` | -| `/admin/setting/system_config` | 系统设置 | Admin后台 | 否 | 系统基础配置 | `src/pages/setting/setSystem/index.vue` | -| `/admin/setting/system_role/index` | 身份管理 | Admin后台 | 否 | 管理员角色管理 | `src/pages/setting/systemRole/index.vue` | -| `/admin/setting/system_admin/index` | 管理员列表 | Admin后台 | 否 | 管理员账户管理 | `src/pages/setting/systemAdmin/index.vue` | -| `/admin/marketing/store_combination/index` | 拼团商品 | Admin后台 | 否 | 拼团活动商品管理 | `src/pages/marketing/storeCombination/index.vue` | -| `/admin/marketing/store_coupon_issue/index` | 优惠券 | Admin后台 | 否 | 优惠券发放管理 | `src/pages/marketing/storeCouponIssue/index.vue` | -| `/admin/system/log` | 前端日志 | Admin后台 | 否 | 系统日志查看 | `src/pages/system/log/index.vue` | - -**来源**: `src/router/modules/*.js` 文件中的路由配置 - -## 2. 页面关系树 - -``` -CRMEB Admin 后台系统 -├── 主页 (home_index) -│ ├── 基础信息展示 (baseInfo) -│ ├── 快捷菜单 (gridMenu) -│ ├── 访问统计图表 (visitChart) -│ └── 用户统计图表 (userChart) -├── 商品管理 (product) -│ ├── 商品列表 (productList) -│ │ ├── 搜索筛选区 -│ │ ├── 商品列表表格 -│ │ └── 操作按钮区 -│ ├── 商品分类 (productClassify) -│ ├── 添加商品 (productAdd) -│ ├── 商品评论 (productEvaluate) -│ ├── 商品规格 (productAttr) -│ ├── 商品参数 (paramList) -│ └── 商品标签 (labelList) -├── 订单管理 (order) -│ ├── 订单列表 (orderList) -│ ├── 收银订单 (offline) -│ ├── 售后订单 (refund) -│ └── 发票管理 (invoice) -├── 用户管理 (user) -│ ├── 用户列表 (list) -│ │ ├── 用户搜索筛选 -│ │ ├── 用户列表表格 -│ │ └── 用户详情弹窗 -│ ├── 用户等级 (level) -│ ├── 用户分组 (group) -│ ├── 用户标签 (label) -│ ├── 会员类型 (type) -│ ├── 卡密会员 (card) -│ ├── 会员记录 (record) -│ └── 会员权益 (right) -├── 系统设置 (setting) -│ ├── 系统配置 (setSystem) -│ ├── 身份管理 (systemRole) -│ ├── 管理员列表 (systemAdmin) -│ ├── 消息管理 (notification) -│ ├── 物流配置 (logistics) -│ ├── 短信配置 (sms) -│ ├── 商城配置 (config) -│ ├── 主题风格 (themeStyle) -│ ├── 店铺装修 (devise) -│ ├── 客服管理 (service) -│ ├── 城市数据 (dada) -│ ├── 运费模板 (templates) -│ ├── 提货点管理 (store) -│ ├── 核销员管理 (staff) -│ └── 核销订单 (order) -├── 营销活动 (marketing) -│ ├── 拼团商品 (combinalist) -│ ├── 优惠券 (storeCouponIssue) -│ ├── 秒杀商品 (storeSeckill) -│ ├── 积分商品 (storeIntegral) -│ └── 砍价商品 (bargain) -├── 财务管理 (finance) -│ ├── 财务对账 (financeList) -│ ├── 资金记录 (capitalFlow) -│ ├── 佣金记录 (commissionList) -│ ├── 提现申请 (extractList) -│ └── 账单记录 (billList) -├── 系统管理 (system) -│ ├── 代码生成 (codeGeneration) -│ ├── 文件管理 (fileList) -│ ├── 维护管理 (maintain) -│ └── 数据配置 (groupData) -├── 应用管理 (app) -│ ├── 微信菜单 (wechatMenu) -│ ├── 微信回复 (wechatReply) -│ └── 微信用户 (wechatUser) -└── 统计报表 (statistic) - ├── 产品统计 (productStatistic) - ├── 用户统计 (userStatistic) - ├── 订单统计 (orderStatistic) - └── 交易统计 (transactionStatistic) -``` - -## 3. 页面区域-文件映射表 - -### 3.1 主页 (home_index) - -| 区域名 | 对应组件/文件 | 说明 | 关键状态 | 关键接口 | -|-------|---------------|------|---------|---------| -| 基础信息展示区 | `src/pages/index/components/baseInfo.vue` | 显示今日/昨日数据对比和总计信息 | infoList数组 | `headerApi` (来源: `src/api/index.js`) | -| 快捷菜单区 | `src/pages/index/components/gridMenu.vue` | 九宫格快捷入口菜单 | - | - | -| 访问统计图表 | `src/pages/index/components/visitChart.vue` | 订单统计图表展示 | visitType, visitDate | - | -| 用户统计图表 | `src/pages/index/components/userChart.vue` | 用户数据统计图表 | - | - | -| 页面布局容器 | `src/pages/index/index.vue` | 主页布局容器,组合上述组件 | userInfo | `auth()` (来源: `src/api/system.js`) | -| Vuex状态 | `src/store/module/userInfo.js` | 用户信息状态管理 | userInfo | - | - -**来源**: `src/pages/index/index.vue` (行7-15), `src/store/module/userInfo.js` - -### 3.2 商品列表页面 (product_productList) - -| 区域名 | 对应组件/文件 | 说明 | 关键状态 | 关键接口 | -|-------|---------------|------|---------|---------| -| 搜索筛选区 | 内联在页面模板中 | 商品名称、类型、分类、配送方式等筛选条件 | artFrom表单对象 | - | -| 商品列表表格 | 内联在页面模板中 | 商品数据表格展示,包含分页 | tableData数组 | `productList()` (来源: `src/api/product.js`) | -| 操作按钮区 | 内联在页面模板中 | 批量操作、添加商品等按钮 | - | - | -| 页面布局容器 | `src/pages/product/productList/index.vue` | 商品管理主页面 | artFrom, tableData, loading | `productList()`, `productStatus()` (来源: `src/api/product.js`) | - -**来源**: `src/pages/product/productList/index.vue` (行1-50), `src/api/product.js` - -### 3.3 用户列表页面 (user_list) - -| 区域名 | 对应组件/文件 | 说明 | 关键状态 | 关键接口 | -|-------|---------------|------|---------|---------| -| 用户搜索筛选区 | 内联在页面模板中 | 用户昵称、等级、分组等筛选条件 | userFrom表单对象, field_key | - | -| 用户列表表格 | 内联在页面模板中 | 用户数据表格,包含用户信息展示 | tableData数组 | `userList()` (来源: `src/api/user.js`) | -| 用户详情弹窗 | `src/pages/user/list/handle/userDetails.vue` | 用户详细信息弹窗组件 | visible, userInfo | - | -| 用户编辑弹窗 | `src/pages/user/list/handle/userEdit.vue` | 用户信息编辑弹窗 | visible, editForm | `userEdit()` (来源: `src/api/user.js`) | -| 页面布局容器 | `src/pages/user/list/index.vue` | 用户管理主页面 | userFrom, tableData, collapse | `userList()`, `userLevel()`, `userGroup()` (来源: `src/api/user.js`) | - -**来源**: `src/pages/user/list/index.vue` (行1-100), `src/api/user.js` - -## 4. 文件职责清单 - -### 4.1 Pages 目录文件职责 - -#### 主页相关 (src/pages/index/) -- `index.vue`: 主页容器组件,组合统计组件,处理用户认证 -- `components/baseInfo.vue`: 基础统计信息卡片展示 -- `components/gridMenu.vue`: 快捷操作菜单网格 -- `components/visitChart.vue`: 访问统计图表组件 -- `components/userChart.vue`: 用户统计图表组件 - -#### 商品管理 (src/pages/product/) -- `productList/index.vue`: 商品列表页面,包含搜索、筛选、表格展示 -- `productClassify/index.vue`: 商品分类管理页面 -- `productAdd/index.vue`: 商品添加/编辑页面 -- `productReply/index.vue`: 商品评论管理页面 -- `productAttr/index.vue`: 商品规格管理页面 -- `paramList/index.vue`: 商品参数管理页面 -- `labelList/index.vue`: 商品标签管理页面 - -#### 订单管理 (src/pages/order/) -- `orderList/index.vue`: 订单列表管理页面 -- `offline/index.vue`: 收银订单管理页面 -- `refund/index.vue`: 售后订单管理页面 -- `invoice/index.vue`: 发票管理页面 - -#### 用户管理 (src/pages/user/) -- `list/index.vue`: 用户列表主页面 -- `list/handle/userDetails.vue`: 用户详情弹窗组件 -- `list/handle/userEdit.vue`: 用户编辑弹窗组件 -- `list/handle/userEditForm.vue`: 用户编辑表单组件 -- `list/handle/userInfo.vue`: 用户信息展示组件 -- `list/tableExpand.vue`: 用户列表表格展开组件 -- `level/index.vue`: 用户等级管理页面 -- `group/index.vue`: 用户分组管理页面 -- `label/index.vue`: 用户标签管理页面 - -#### 系统设置 (src/pages/setting/) -- `setSystem/index.vue`: 系统配置主页面 -- `systemRole/index.vue`: 管理员角色管理页面 -- `systemAdmin/index.vue`: 管理员列表管理页面 -- `notification/index.vue`: 消息管理页面 -- `notification/notificationEdit.vue`: 消息编辑页面 -- `membershipLevel/index.vue`: 分销等级管理页面 -- `freight/index.vue`: 物流公司管理页面 -- `cityDada/index.vue`: 城市数据管理页面 -- `shippingTemplates/index.vue`: 运费模板管理页面 -- `storeList/index.vue`: 提货点管理页面 -- `clerkList/index.vue`: 核销员管理页面 -- `verifyOrder/index.vue`: 核销订单管理页面 -- `themeStyle/index.vue`: 主题风格设置页面 -- `devise/list.vue`: 店铺装修页面 -- `devisePage/index.vue`: 页面设计页面 -- `link.vue`: 链接管理页面 -- `storage.vue`: 存储配置页面 -- `ticket.vue`: 打印机设置页面 -- `agreement/index.vue`: 协议设置页面 - -#### 营销活动 (src/pages/marketing/) -- `storeCombination/index.vue`: 拼团商品管理页面 -- `storeCombination/combinaList.vue`: 拼团列表页面 -- `storeCouponIssue/index.vue`: 优惠券管理页面 -- `storeSeckill/index.vue`: 秒杀商品管理页面 -- `storeIntegral/index.vue`: 积分商品管理页面 -- `storeBargain/index.vue`: 砍价商品管理页面 - -#### 财务管理 (src/pages/finance/) -- `financeList/index.vue`: 财务对账页面 -- `capitalFlow/index.vue`: 资金记录页面 -- `commissionList/index.vue`: 佣金记录页面 -- `extractList/index.vue`: 提现申请页面 -- `billList/index.vue`: 账单记录页面 - -#### 系统管理 (src/pages/system/) -- `codeGeneration/index.vue`: 代码生成页面 -- `fileList/index.vue`: 文件管理页面 -- `maintain/index.vue`: 维护管理页面 -- `group/list.vue`: 数据配置页面 - -#### 应用管理 (src/pages/app/) -- `wechatMenu/index.vue`: 微信菜单管理页面 -- `wechatReply/index.vue`: 微信回复管理页面 -- `wechatUser/index.vue`: 微信用户管理页面 - -#### 统计报表 (src/pages/statistic/) -- `productStatistic/index.vue`: 产品统计页面 -- `userStatistic/index.vue`: 用户统计页面 -- `orderStatistic/index.vue`: 订单统计页面 -- `transactionStatistic/index.vue`: 交易统计页面 - -### 4.2 Components 目录文件职责 - -#### 通用组件 (src/components/) -- `common-icon/`: 通用图标组件 -- `copyright/`: 版权信息组件 -- `Pagination/`: 分页组件 -- `parent-view/`: 父视图组件 -- `publicSearchFrom/`: 公共搜索表单组件 -- `searchFrom/`: 搜索表单组件 -- `uploadImg/`: 图片上传组件 -- `uploadPictures/`: 多图上传组件 -- `uploadVideo/`: 视频上传组件 -- `uploadVideo2/`: 视频上传组件(增强版) - -#### 表单组件 (src/components/from/) -- `from/`: 通用表单组件 - -#### 图表组件 (src/components/echarts/) -- `echarts/`: ECharts图表基础组件 -- `echartsNew/`: 新版ECharts图表组件 - -#### 移动端配置组件 (src/components/mobileConfig/) -- 包含大量移动端页面配置组件 - -#### 弹窗组件 (src/components/hotpotModal/) -- `hotpotModal/`: 热区弹窗组件 - -#### 编辑器组件 (src/components/wangEditor/) -- `wangEditor/`: 富文本编辑器组件 - -### 4.3 Store 目录文件职责 - -#### Vuex状态管理模块 (src/store/module/) -- `user.js`: 用户登录状态管理 -- `app.js`: 应用全局状态 -- `menus.js`: 菜单数据管理 -- `menu.js`: 当前菜单状态 -- `userInfo.js`: 用户信息管理 -- `userLevel.js`: 用户等级管理 -- `order.js`: 订单相关状态 -- `media.js`: 媒体文件管理 -- `goodSelect.js`: 商品选择状态 -- `moren.js`: 默认配置管理 -- `shopping.js`: 购物相关状态 -- `fresh.js`: 刷新状态管理 -- `kefu.js`: 客服状态管理 -- `integralOrder.js`: 积分订单管理 -- `mobildConfig.js`: 移动端配置 -- `upgrade.js`: 升级状态管理 -- `layout.js`: 布局状态管理 -- `themeConfig.js`: 主题配置 -- `routesList.js`: 路由列表 -- `tagsViewRoutes.js`: 标签页路由 -- `userInfos.js`: 用户信息扩展 -- `keepAliveNames.js`: 缓存页面名称 - -### 4.4 API 目录文件职责 - -#### 接口文件 (src/api/) -- `index.js`: 首页相关接口 -- `account.js`: 账户相关接口 -- `agent.js`: 代理商相关接口 -- `app.js`: 应用相关接口 -- `cms.js`: CMS内容管理接口 -- `common.js`: 通用接口 -- `crud.js`: CRUD通用接口 -- `diy.js`: DIY装修接口 -- `export.js`: 导出相关接口 -- `finance.js`: 财务相关接口 -- `index.js`: 首页统计接口 -- `kefu.js`: 客服相关接口 -- `kefu_mobile.js`: 移动端客服接口 -- `live.js`: 直播相关接口 -- `lottery.js`: 抽奖相关接口 -- `marketing.js`: 营销活动接口 -- `membershipLevel.js`: 会员等级接口 -- `notification.js`: 消息通知接口 -- `order.js`: 订单相关接口 -- `product.js`: 商品相关接口 -- `setting.js`: 设置相关接口 -- `statistic.js`: 统计相关接口 -- `system.js`: 系统相关接口 -- `systemAdmin.js`: 管理员接口 -- `systemBackendRouting.js`: 后端路由接口 -- `systemCodeGeneration.js`: 代码生成接口 -- `systemMenus.js`: 菜单接口 -- `systemOutAccount.js`: 外部账户接口 -- `upload.js`: 上传相关接口 -- `uploadPictures.js`: 图片上传接口 -- `user.js`: 用户相关接口 - -### 4.5 Utils 目录文件职责 - -#### 工具函数 (src/utils/) -- `ase.js`: AES加密工具 -- `authLapse.js`: 认证过期处理 -- `bus.js`: 事件总线 -- `city.js`: 城市数据处理 -- `componentSize.js`: 组件尺寸工具 -- `compressImg.js`: 图片压缩工具 -- `editorImg.js`: 编辑器图片处理 -- `emoji.js`: 表情符号处理 -- `Excel.js`: Excel处理工具 -- `icon.js`: 图标处理工具 -- `index.js`: 工具函数入口 -- `loading.js`: 加载状态管理 -- `modalForm.js`: 弹窗表单工具 -- `newToExcel.js`: 新版Excel导出 -- `public.js`: 公共工具函数 -- `scroll-to.js`: 滚动工具 -- `storage.js`: 本地存储工具 -- `theme.js`: 主题工具 -- `toolsValidate.js`: 表单验证工具 -- `upload.js`: 上传工具 -- `validate.js`: 数据验证工具 -- `videoCloud.js`: 视频云处理 - -### 4.6 Styles 目录文件职责 - -#### 样式文件 (src/theme/) -- `app.scss`: 应用主样式 -- `base.scss`: 基础样式 -- `common/transition.scss`: 过渡动画样式 -- `dark.scss`: 暗色主题 -- `element.scss`: Element UI样式覆盖 -- `iview.scss`: iView样式覆盖 -- `index.scss`: 样式入口文件 -- `loading.scss`: 加载样式 -- `variables.scss`: 样式变量 - -## 5. 未知/缺失信息清单 - -### 5.1 需要补充分析的页面文件 -- `src/pages/kefu/`: 客服模块页面文件(40个文件)- 未详细分析 -- `src/pages/marketing/`: 部分营销活动页面组件 - 未完全追踪依赖关系 -- `src/pages/setting/`: 系统设置下多个子页面 - 未完全分析组件结构 -- `src/pages/system/`: 系统管理页面 - 未详细分析 -- `src/pages/app/`: 应用管理页面 - 未详细分析 -- `src/pages/statistic/`: 统计报表页面 - 未详细分析 - -### 5.2 需要补充的组件依赖 -- `src/components/mobileConfig/`: 35个移动端配置组件 - 未分析具体职责 -- `src/components/mobileConfigRight/`: 39个右侧配置组件 - 未分析具体职责 -- `src/components/mobilePage/`: 28个移动端页面组件 - 未分析具体职责 -- `src/components/mobilePageDiy/`: 23个DIY页面组件 - 未分析具体职责 - -### 5.3 需要补充的API接口分析 -- 大部分API文件只分析了入口,未分析具体接口函数职责 -- 缺少接口参数和返回数据结构分析 - -### 5.4 需要补充的Store状态分析 -- 大部分store模块只分析了入口,未分析具体state/mutations/actions结构 - -### 5.5 需要补充的Utils工具分析 -- 大部分工具文件未分析具体函数功能和使用场景 - -## 6. 架构优化建议 - -### 6.1 组件抽取建议 -1. **搜索筛选组件**: 将各页面的搜索筛选逻辑抽取为通用组件 -2. **数据表格组件**: 标准化列表页面的表格展示组件 -3. **弹窗表单组件**: 统一弹窗编辑表单的结构和交互 -4. **统计卡片组件**: 标准化统计信息展示组件 - -### 6.2 Store模块重组建议 -1. **按业务域重组**: 将相关业务的状态管理集中到一起 -2. **状态规范化**: 统一state的命名和结构规范 -3. **Actions抽象**: 将通用数据操作抽象为通用actions - -### 6.3 API接口重组建议 -1. **按模块分组**: 将API按业务模块重新组织 -2. **接口规范化**: 统一接口命名和参数结构 -3. **错误处理统一**: 标准化API错误处理逻辑 - -### 6.4 Utils工具优化建议 -1. **工具分类**: 按功能类型重新组织工具函数 -2. **通用工具库**: 抽取跨页面使用的通用工具 -3. **类型定义**: 为工具函数添加TypeScript类型定义 - -### 6.5 文件组织优化建议 -1. **组件按功能分组**: 将组件按功能类型重新组织目录结构 -2. **页面组件瘦身**: 将复杂页面的逻辑抽取到composables中 -3. **样式模块化**: 将样式按组件和页面分离组织 - ---- - -**分析说明**: 本文档基于代码静态分析生成,重点分析了页面结构、组件依赖和文件职责关系。由于项目规模较大,部分细节需要进一步深入分析。 \ No newline at end of file diff --git a/docs/admin/PAGE_STRUCTURE_ANALYSIS.md b/docs/admin/PAGE_STRUCTURE_ANALYSIS.md deleted file mode 100644 index 032b689e..00000000 --- a/docs/admin/PAGE_STRUCTURE_ANALYSIS.md +++ /dev/null @@ -1,292 +0,0 @@ -# CRMEB Admin 页面结构与流转分析 - -## 项目概述 -- **项目**: CRMEB Admin 电商管理后台 -- **技术栈**: Vue.js + Vue Router + Element UI + Vuex -- **路由前缀**: `/admin` (可配置) -- **路由模式**: history - -## 1. 应用入口结构 - -### 1.1 入口文件层级 -``` -main.js (应用入口) -├── Vue实例初始化 - - -├── 路由器配置 -├── Vuex状态管理 -└── 全局组件/插件注册 - -App.vue (根组件) -├── router-view (主路由出口) -└── Setings组件 (布局设置弹窗) -``` - -**源码位置**: -- `src/main.js` (line 250-256): Vue实例创建 -- `src/App.vue` (line 3): 根路由视图 - -## 2. 页面布局体系 - -### 2.1 布局组件层级 -``` -LayoutMain (主布局组件) -├── layout/index.vue (布局选择器) -│ ├── 根据主题配置选择布局类型 -│ ├── 支持4种布局模式 -│ └── 响应式适配 -│ -├── layout/main/defaults.vue (默认布局) -│ ├── Asides (侧边栏) -│ ├── Headers (顶部导航栏) -│ └── Mains (主内容区) -│ -└── layout/component/main.vue (主内容容器) - ├── LayoutParentView (路由视图容器) - ├── Footers (页脚) - ├── Links (链接页面) - └── Iframes (内嵌页面) -``` - -**源码位置**: -- `src/layout/index.vue` (line 3-8): 布局选择逻辑 -- `src/layout/main/defaults.vue` (line 2-11): 默认布局结构 -- `src/layout/component/main.vue` (line 9): 路由视图 - -### 2.2 路由视图容器 -``` -LayoutParentView (父级路由视图) -├── transition (页面切换动画) -├── keep-alive (页面缓存) -└── router-view (实际路由出口) -``` - -**源码位置**: `src/layout/routerView/parent.vue` - -## 3. 路由配置体系 - -### 3.1 路由分类结构 -``` -路由配置 (src/router/routers.js) -├── frameIn (主框架内路由) -│ ├── 基础路径: / -│ ├── 使用LayoutMain布局 -│ ├── 包含所有业务模块 -│ └── 需要权限验证 -│ -├── frameOuts (主框架外路由) -│ ├── 登录页面 -│ ├── 客服模块 -│ ├── 特殊功能页面 -│ └── 无需权限验证 -│ -└── errorPage (错误页面) - ├── 403/404/500错误页 - └── 通配符路由兜底 -``` - -### 3.2 路由模块组织 -``` -src/router/modules/ -├── index.js # 首页模块 -├── product.js # 商品管理 -├── order.js # 订单管理 -├── user.js # 用户管理 -├── setting.js # 系统设置 -├── marketing.js # 营销活动 -├── finance.js # 财务管理 -├── system.js # 系统管理 -├── app.js # 应用管理 -├── statistic.js # 统计报表 -├── frameOut.js # 框架外路由 -├── crud.js # CRUD模块 -├── division.js # 部门管理 -└── agent.js # 代理商管理 -``` - -## 4. 页面流转逻辑 - -### 4.1 应用启动流程 -``` -应用启动 -├── main.js 初始化Vue实例 -├── 注册全局组件和插件 -├── 配置路由和状态管理 -└── 挂载到 #app 元素 - -页面初次加载 -├── App.vue 渲染 -├── 路由器检查当前路径 -├── 匹配路由配置 -└── 渲染对应组件 -``` - -### 4.2 登录认证流程 -``` -访问受保护页面 -├── router.beforeEach 路由守卫拦截 -├── 检查用户token -│ ├── 有token → 验证权限 -│ └── 无token → 跳转登录页 -├── 权限验证 -│ ├── 有权限 → 允许访问 -│ └── 无权限 → 跳转403页 -└── 渲染目标页面 -``` - -**源码位置**: `src/router/index.js` (line 116-169) - -### 4.3 页面导航流程 -``` -用户点击导航 -├── 触发路由变化 ($route变化) -├── layout/index.vue 监听路由变化 -├── 更新面包屑导航 -├── 更新标签页导航 -├── LayoutParentView 处理页面切换 -│ ├── 检查keep-alive缓存 -│ ├── 执行页面切换动画 -│ └── 渲染新页面组件 -└── 滚动到页面顶部 -``` - -### 4.4 布局切换流程 -``` -用户切换布局主题 -├── Vuex状态更新 (themeConfig) -├── layout/index.vue 响应状态变化 -├── 根据配置选择布局组件 -├── 重新渲染布局结构 -└── 保持页面内容不变 -``` - -## 5. 关键页面路径 - -### 5.1 主框架内页面 (frameIn) -| 路径 | 页面名称 | 组件位置 | 权限要求 | -|------|---------|---------|---------| -| `/admin/index` | 主页 | `src/pages/index/index.vue` | `admin-index-index` | -| `/admin/product/product_list` | 商品管理 | `src/pages/product/productList/index.vue` | `admin-store-storeProuduct-index` | -| `/admin/order/list` | 订单管理 | `src/pages/order/orderList/index.vue` | `admin-order-storeOrder-index` | -| `/admin/user/list` | 用户管理 | `src/pages/user/list/index.vue` | `admin-user-user-index` | -| `/admin/setting/system_config` | 系统设置 | `src/pages/setting/setSystem/index.vue` | `setting-system-config` | - -### 5.2 主框架外页面 (frameOut) -| 路径 | 页面名称 | 组件位置 | 说明 | -|------|---------|---------|------| -| `/admin/login` | 登录页面 | `src/pages/account/login/index.vue` | 无需登录即可访问 | -| `/kefu` | 客服管理 | `src/pages/kefu/index.vue` | 独立客服系统 | -| `/kefu/mobile_chat` | 移动端客服 | `src/pages/kefu/mobile/index.vue` | 移动端聊天界面 | -| `/app/upload` | 文件上传 | `src/pages/app/upload.vue` | 移动端扫码上传 | - -## 6. 页面缓存机制 - -### 6.1 Keep-Alive 配置 -```javascript -// src/layout/routerView/parent.vue - - - -``` - -### 6.2 缓存管理 -``` -缓存页面列表 -├── 从Vuex获取 (keepAliveNames) -├── 支持页面刷新功能 -├── 标签页关闭时清理缓存 -└── 路由切换时保持状态 -``` - -**源码位置**: `src/store/module/keepAliveNames.js` - -## 7. 页面布局类型 - -### 7.1 支持的布局模式 -``` -defaults (默认布局) -├── 经典的左右布局 -├── 侧边栏 + 主内容区 -└── 支持固定头部 - -classic (经典布局) -├── 传统管理后台布局 -├── 顶部导航 + 侧边栏 -└── 适用于复杂导航 - -transverse (横向布局) -├── 横向菜单布局 -├── 适用于扁平化导航 -└── 节省垂直空间 - -columns (分栏布局) -├── 多列布局设计 -├── 适用于信息密集页面 -└── 提高空间利用率 -``` - -**源码位置**: `src/layout/main/` 目录下对应文件 - -## 8. 特殊页面处理 - -### 8.1 全屏页面 -```javascript -// 路由meta配置 -meta: { - fullScreen: true // 启用全屏模式 -} -``` -- 隐藏侧边栏和顶部导航 -- 适用于页面设计器等特殊场景 - -### 8.2 内嵌页面 -```javascript -// 路由meta配置 -meta: { - isIframe: true, // 内嵌iframe - isLink: true // 链接页面 -} -``` -- 支持iframe内嵌外部页面 -- 支持直接跳转外部链接 - -### 8.3 标签页固定 -```javascript -// 路由meta配置 -meta: { - isAffix: true // 固定标签页 -} -``` -- 标签页不可关闭 -- 通常用于首页等重要页面 - -## 9. 响应式适配 - -### 9.1 移动端适配 -``` -屏幕宽度检测 -├── < 600px → Mobile模式 -├── 600-992px → Tablet模式 -├── > 992px → Desktop模式 - -布局自适应 -├── 移动端隐藏侧边栏 -├── 自动切换到单列布局 -└── 调整组件尺寸 -``` - -**源码位置**: `src/App.vue` (line 33-49) - -## 10. 总结 - -CRMEB Admin的页面结构采用了典型的管理后台架构: - -1. **分层设计**: 入口层 → 布局层 → 路由层 → 页面层 -2. **模块化组织**: 路由按业务模块拆分,便于维护 -3. **灵活布局**: 支持多种布局模式,适应不同使用场景 -4. **权限控制**: 基于路由的权限验证体系 -5. **缓存优化**: 智能的页面缓存机制提升用户体验 -6. **响应式适配**: 支持多终端访问 - -这种架构设计使得系统具有良好的可扩展性和维护性,同时提供了丰富的定制化选项。 \ No newline at end of file diff --git a/docs/admin/UNI_APP_X_PAGE_FIX_GUIDE.md b/docs/admin/UNI_APP_X_PAGE_FIX_GUIDE.md deleted file mode 100644 index 8815fbed..00000000 --- a/docs/admin/UNI_APP_X_PAGE_FIX_GUIDE.md +++ /dev/null @@ -1,1612 +0,0 @@ -# uni-app-x 页面修复指南 - -## 📋 文档概述 - -本文档总结了 uni-app-x 项目中页面配置和编译错误的完整修复流程,旨在为后续开发提供标准化的解决方案和最佳实践。 - -## 🔍 问题根源分析 - -### 1. 初始错误现象 - -``` -[plugin:uni:h5-pages-json] 页面"minimal"不存在,请确保填写的页面路径不包含文件后缀,且必须与真实的文件路径大小写保持一致。 -``` - -``` -SyntaxError: The requested module '.../vue.runtime.esm.js' does not provide an export named 'onLoad' -``` - -### 2. 根本原因总结 - -#### **原因一:pages.json 路径配置错误** - -- **错误格式**: `"path": "pages/minimal"` (主页面缺少完整路径) -- **错误格式**: `"path": "pages/mall/admin/index"` (主页面错误包含完整路径) -- **错误格式**: 子包路径配置不完整 - -#### **原因二:AdminLayout 组件语法错误** - -- **重复闭合标签**: ` 标签 --> - - - - - -``` - -#### **步骤 2.2:修复生命周期导入** - -```javascript -// ❌ 错误:从 Vue 导入 uni-app 生命周期 -import { ref, computed, onLoad } from "vue"; - -// ✅ 正确:uni-app-x 生命周期全局可用 -import { ref, computed } from "vue"; - -// 在组件中直接使用 -onLoad(() => { - activeMenu.value = props.currentPage; -}); -``` - -#### **步骤 2.3:验证组件结构** - -```vue - -``` - -### **阶段三:页面配置恢复** - -#### **步骤 3.1:恢复主页面配置** - -```json -{ - "pages": [ - { - "path": "pages/minimal", - "style": { - "navigationBarTitleText": "最小测试" - } - }, - { - "path": "pages/mall/admin/index", - "style": { - "navigationBarTitleText": "管理后台", - "navigationStyle": "custom" - } - } - ] -} -``` - -#### **步骤 3.2:恢复子包配置** - -```json -{ - "subPackages": [ - { - "root": "pages/mall", - "pages": [ - { - "path": "admin/user-management", - "style": { - "navigationBarTitleText": "用户管理", - "navigationStyle": "custom" - } - } - // ... 其他页面 - ] - } - ] -} -``` - -#### **步骤 3.3:验证完整配置** - -```json -{ - "pages": [ - { - "path": "pages/minimal", - "style": { "navigationBarTitleText": "最小测试" } - }, - { - "path": "pages/mall/admin/index", - "style": { - "navigationBarTitleText": "管理后台", - "navigationStyle": "custom" - } - } - ], - "subPackages": [ - { - "root": "pages/mall", - "pages": [ - { - "path": "admin/user-management", - "style": { - "navigationBarTitleText": "用户管理", - "navigationStyle": "custom" - } - }, - { - "path": "admin/product-management", - "style": { - "navigationBarTitleText": "商品管理", - "navigationStyle": "custom" - } - }, - { - "path": "admin/order-management", - "style": { - "navigationBarTitleText": "订单管理", - "navigationStyle": "custom" - } - }, - { - "path": "admin/finance-management", - "style": { - "navigationBarTitleText": "财务管理", - "navigationStyle": "custom" - } - }, - { - "path": "admin/system-settings", - "style": { - "navigationBarTitleText": "系统设置", - "navigationStyle": "custom" - } - } - ] - } - ], - "globalStyle": { - "navigationBarTextStyle": "black", - "navigationBarTitleText": "mall", - "navigationBarBackgroundColor": "#FFFFFF", - "backgroundColor": "#F8F8F8" - } -} -``` - -### **阶段四:路径格式统一** - -### **阶段五:特殊字符处理** - -#### **步骤 5.1:移除问题 Emoji 字符** - -```vue - - - - - -``` - -**常见问题 Emoji 及替代方案**: - -```javascript -// 统计图标 -'👥' → '👤' // 用户数量 -'✅' → '✓' // 成功/活跃 -'🚫' → '✗' // 禁用/下架 -'📦' → '□' // 商品/包裹 -'⏳' → '○' // 等待/处理中 -'🚚' → '→' // 配送中 -'⚠️' → '!' // 警告/库存不足 - -// 财务图标 -'💰' → '$' // 收入 -'📈' → '↑' // 增长 -'📊' → '≡' // 图表 -'💳' → '■' // 账户 -``` - -#### **步骤 5.2:检查文件编码** - -```bash -# 检查文件编码和特殊字符 -file pages/mall/admin/*.uvue - -# 确保文件编码为 UTF-8 无 BOM -# 移除任何不可见字符 -``` - -#### **步骤 5.3:验证模板语法完整性** - -```vue - - -``` - -#### **步骤 5.4:最终验证** - -### **阶段六:缩进一致性检查** - -#### **步骤 6.1:统一缩进方式** - -```vue - - - - - -``` - -#### **步骤 6.2:检查缩进工具** - -```bash -# 检查文件中是否存在制表符 -grep -P '\t' pages/mall/admin/*.uvue - -# 将制表符转换为空格(2个空格) -sed -i 's/\t/ /g' pages/mall/admin/*.uvue -``` - -#### **步骤 6.3:验证标签闭合** - -```javascript -// 检查所有开始标签都有对应结束标签 -// 检查缩进一致性 -// 确保没有多余的闭合标签 -``` - -#### **步骤 6.4:最终验证** - -### **阶段七:方法调用检查** - -#### **步骤 7.1:检查方法引用** - -```javascript -// ❌ 错误:方法名已更改但模板未更新 - - -// ✅ 正确:更新方法引用 - -``` - -#### **步骤 7.2:验证方法定义** - -```javascript -// 确保所有模板中引用的方法都已定义 -const newMethodName = () => { - // 方法实现 -}; -``` - -#### **步骤 7.3:检查参数匹配** - -```javascript -// 确保方法调用时的参数与定义一致 -const handleClick = (param: string) => { - console.log(param) -} - -// 模板调用 - -``` - -#### **步骤 7.4:最终验证** - -### **阶段八:自闭合标签检查** - -#### **步骤 8.1:检查自闭合标签格式** - -```vue - - - - - - - - - - - - - -``` - -#### **步骤 8.2:自动修复工具** - -```bash -# 使用 sed 批量修复(注意备份文件) -sed -i 's/><\/image>/ \/>/g' pages/mall/admin/*.uvue -sed -i 's/><\/checkbox>/ \/>/g' pages/mall/admin/*.uvue -``` - -#### **步骤 8.3:验证标签完整性** - -```javascript -// 检查所有自闭合标签都正确结束 -// 确保没有多余的结束标签 -``` - -### **阶段九:模态框位置优化** - -#### **步骤 9.1:识别模态框位置问题** - -```vue - - - - - -``` - -#### **步骤 9.2:重构模态框位置** - -```vue - -``` - -#### **步骤 9.3:验证模态框行为** - -```javascript -// 确保模态框在所有页面模式下都能正常显示 -// 测试不同条件下的模态框显示 -``` - -#### **步骤 9.4:最终验证** - -### **阶段十:.uvue文件特殊处理** - -#### **步骤 10.1:简化复杂模板** - -```vue - - - - - -``` - -#### **步骤 10.2:移除问题Unicode字符** - -```vue - - - - - - - - - -Y - -N - -* - -``` - -#### **步骤 10.3:UTS编译器兼容性检查** - -```javascript -// 检查UTS特定的语法要求 -// 确保所有导入和类型定义正确 -// 验证组件Props和事件处理 -``` - -#### **步骤 10.4:渐进式开发策略** - -```javascript -// 1. 从最小可用模板开始 -const minimalTemplate = ` - -`; - -// 2. 逐步添加功能,每次只添加一个特性 -// 3. 每次修改后立即编译测试 -// 4. 出现问题时立即回滚到上一个稳定版本 -``` - -#### **步骤 10.5:最终验证** - -### **阶段十一:批量.uvue文件修复** - -### **阶段十二:AdminLayout双侧边栏布局** - -#### **步骤 11.1:识别问题文件** - -```bash -# 检查所有.uvue文件是否正常编译 -# 记录出现"Invalid end tag"错误的文件 -# 按优先级排序修复顺序 -``` - -#### **步骤 11.2:批量简化模板** - -```javascript -// 为每个问题文件创建最小可用模板 -const minimalTemplates = { - "user-management.uvue": ` - - - - - - `, - - "product-management.uvue": ` - - - - - - `, - - // 为其他页面创建类似的模板 -}; -``` - -#### **步骤 11.3:统一字符替换** - -```bash -# 批量替换所有.uvue文件中的问题字符 -find pages/mall/admin -name "*.uvue" -exec sed -i \ - -e 's/👤/U/g' \ - -e 's/✓/Y/g' \ - -e 's/✗/N/g' \ - -e 's/★/*/g' \ - -e 's/📦/□/g' \ - -e 's/⏳/○/g' \ - -e 's/🚚/→/g' \ - {} \; -``` - -#### **步骤 11.4:验证批量修复** - -```javascript -// 检查所有文件是否正常编译 -// 确认没有"Invalid end tag"错误 -// 测试基本页面导航功能 -``` - -#### **步骤 11.5:最终验证** - -#### **步骤 12.1:设计双侧边栏布局** - -```vue - - - - - -``` - -#### **步骤 12.2:实现菜单数据结构** - -```javascript -const menuList = ref([ - { - id: "user", - title: "用户管理", - icon: "icon-user", - path: "/pages/mall/admin/user-management", - subMenus: [ - { - id: "user-list", - title: "用户列表", - path: "/pages/mall/admin/user-management", - }, - { - id: "user-add", - title: "添加用户", - path: "/pages/mall/admin/user-management?action=add", - }, - ], - }, - { - id: "product", - title: "商品管理", - icon: "icon-product", - path: "/pages/mall/admin/product-management", - subMenus: [ - { - id: "product-list", - title: "商品列表", - path: "/pages/mall/admin/product-management", - }, - { - id: "category", - title: "商品分类", - path: "/pages/mall/admin/product-management?tab=category", - }, - ], - }, - // 没有子菜单的页面 - { - id: "statistics", - title: "用户统计", - icon: "icon-statistics", - path: "/pages/mall/admin/user-statistics", - }, -]); -``` - -#### **步骤 12.3:计算属性实现** - -```javascript -// 计算当前菜单的子菜单 -const activeSubMenus = computed(() => { - const menu = menuList.value.find((m) => m.id === activeMenu.value); - return menu ? menu.subMenus || [] : []; -}); - -// 判断是否有子菜单 -const hasSubMenus = computed(() => { - return activeSubMenus.value.length > 0; -}); -``` - -#### **步骤 12.4:菜单点击处理** - -```javascript -const handleMenuClick = (menu: any) => { - activeMenu.value = menu.id - // 设置默认子菜单(如果有的话) - activeSubMenu.value = menu.subMenus && menu.subMenus.length > 0 ? menu.subMenus[0].id : '' - - // 导航到菜单路径 - uni.navigateTo({ - url: menu.path - }) -} - -const handleSubMenuClick = (subMenu: any) => { - activeSubMenu.value = subMenu.id - // 导航到子菜单路径(可能包含查询参数) - uni.navigateTo({ - url: subMenu.path - }) -} -``` - -#### **步骤 12.5:样式实现** - -```scss -/* 主侧边栏 */ -.admin-sider { - width: 200px; - background-color: #001529; - position: fixed; - left: 0; - top: 0; - bottom: 0; - z-index: 1000; -} - -/* 主内容区 */ -.admin-main { - margin-left: 200px; - display: flex; - min-height: 100vh; -} - -/* 内容侧边栏 */ -.content-sider { - width: 180px; - background-color: #ffffff; - border-right: 1px solid #e8e8e8; - box-shadow: 2px 0 8px rgba(0, 0, 0, 0.06); -} - -.content-sub-menu-item { - height: 36px; - padding: 0 16px; - cursor: pointer; - transition: all 0.2s; - - &.active { - background-color: #e6f7ff; - color: #1890ff; - border-right: 2px solid #1890ff; - } -} - -/* 内容区域 */ -.content-area { - flex: 1; - background-color: #f0f2f5; -} -``` - -#### **步骤 12.6:响应式设计** - -```scss -@media (max-width: 768px) { - .admin-sider { - width: 160px; - } - - .admin-main { - margin-left: 160px; - } - - .content-sider { - width: 140px; - } -} -``` - -#### **步骤 12.7:最终验证** - -### **阶段十四:绝对路径强制规范** - -#### **步骤 14.1:识别相对路径问题** - -```vue - - - - - -``` - -**为什么相对路径会导致问题**: - -- uni-app-x 的 UTS 编译器对相对路径解析不稳定 -- 相对路径在子包结构中容易出错 -- 重构文件位置后需要手动更新所有相对路径 -- 可能导致批量 500 编译错误 - -#### **步骤 14.2:批量替换相对路径** - -```powershell -# 批量替换所有相对路径为绝对路径 -Get-ChildItem "pages" -Recurse -Filter "*.uvue" | ForEach-Object { - (Get-Content $_.FullName -Raw) ` - -replace "from '\.\./\.\./marketing\.uts'", "from '@/pages/mall/admin/marketing/marketing.uts'" ` - -replace "from '\./marketing\.uts'", "from '@/pages/mall/admin/marketing/marketing.uts'" ` - | Set-Content $_.FullName -NoNewline -} -``` - -#### **步骤 14.3:绝对路径映射规则** - -```javascript -// 相对路径 → 绝对路径映射表 -'../../marketing.uts' → '@/pages/mall/admin/marketing/marketing.uts' -'./marketing.uts' → '@/pages/mall/admin/marketing/marketing.uts' -'../../../layouts/admin/...' → '@/layouts/admin/...' -'../../components/...' → '@/components/...' -'../utils/...' → '@/utils/...' - -// ⚠️ 常见错误路径 -'@/layouts/admin/marketing/marketing.uts' // ✗ 错误!marketing.uts 不在 layouts 目录 -'@/pages/mall/admin/marketing/marketing.uts' // ✓ 正确路径 -``` - -**批量替换验证**: - -```powershell -# 验证是否有错误路径残留 -Select-String -Path "pages\mall\admin\marketing\**\*.uvue" -Pattern "from '@/layouts/admin/marketing" -# 应该返回 0 个结果 -``` - -#### **步骤 14.4:验证绝对路径** - -```bash -# 检查是否还有相对路径 -grep -r "from '\.\." pages/ -grep -r 'from "\.\.' pages/ - -# 应该没有任何匹配结果 -``` - -#### **步骤 14.5:最终验证** - -### **阶段十三:AdminLayout代码清理** - -#### **步骤 13.1:移除遗留变量引用** - -```javascript -// ❌ 错误:引用已删除的变量 -const handleMenuClick = (menu: any) => { - activeMenu.value = menu.id - // 引用不存在的 tabs 变量 - const existingTab = tabs.value.find(tab => tab.id === menu.id) - // ... -} - -// ✅ 修复:移除所有遗留引用 -const handleMenuClick = (menu: any) => { - activeMenu.value = menu.id - activeSubMenu.value = menu.subMenus?.[0]?.id || '' - - uni.navigateTo({ url: menu.path }) -} -``` - -#### **步骤 13.2:检查计算属性完整性** - -```javascript -// 确保所有模板中使用的属性都已定义 -const activeSubMenuTitle = computed(() => { - const subMenu = activeSubMenus.value.find(sm => sm.id === activeSubMenu.value) - return subMenu ? subMenu.title : '' -}) - -// 模板中使用 -{{ activeSubMenuTitle }} -``` - -#### **步骤 13.3:验证模板依赖** - -```vue - - -``` - -#### **步骤 13.4:最终验证** - -### **阶段十二:AdminLayout组件解析修复** - -#### **步骤 12.1:检查组件导入路径** - -```javascript -// ❌ 错误:缺少文件扩展名 -import AdminLayout from "@/layouts/admin/index"; - -// ❌ 错误:路径不存在 -import AdminLayout from "@/layout/admin/index.uvue"; - -// ✅ 正确:完整路径包含扩展名 -import AdminLayout from "@/layouts/admin/index.uvue"; -``` - -#### **步骤 12.2:简化组件结构** - -```vue - - - - - - - -``` - -#### **步骤 12.3:验证组件可用性** - -```javascript -// 在页面中正确使用组件 - -``` - -#### **步骤 12.4:UTS编译器兼容性** - -```javascript -// 确保组件语法符合UTS要求 -// 使用 -``` - -### **原理五:错误排查方法** - -#### **逐步验证策略**: - -1. **最小化配置**: 从最简单的配置开始 -2. **逐步添加**: 每次只添加一个功能 -3. **错误定位**: 根据错误信息快速定位问题 -4. **备份恢复**: 修改前备份,失败时快速回滚 - -#### **常见错误检查清单**: - -- ✅ pages.json 路径格式是否正确 -- ✅ 页面文件是否存在 -- ✅ 组件语法是否正确 -- ✅ **导入语句必须使用 `@/...` 绝对路径(禁止相对路径)** -- ✅ 生命周期钩子使用是否正确 -- ✅ 响应式数据使用是否正确 -- ✅ 特殊字符和 emoji 是否安全 -- ✅ 缩进是否一致(避免混用制表符和空格) -- ✅ 方法调用是否正确(方法名和参数匹配) -- ✅ 自闭合标签格式是否正确(使用 `/>` 而非 `>`) -- ✅ 模态框位置是否正确(避免条件嵌套) -- ✅ .uvue文件复杂度是否适中(避免过度复杂的模板结构) -- ✅ 批量文件修复是否完整(所有.uvue文件都已简化处理) -- ✅ AdminLayout组件是否正确导入和解析 -- ✅ AdminLayout代码清理是否完整(无遗留变量引用) - -## 🚀 最佳实践指南 - -### **开发规范** - -#### **1. 文件命名规范** - -- 页面文件: `kebab-case.uvue` -- 组件文件: `PascalCase.uvue` -- 工具文件: `camelCase.uts` - -#### **2. 路径配置规范** - -- 主页面: `pages/page-name` -- 子包页面: `root: "pages/module"`, `path: "sub-page"` -- 组件导入: `@/layouts/...`, `@/components/...` - -#### **3. 代码组织规范** - -```vue - - - - - -``` - -### **调试技巧** - -#### **1. 编译错误排查** - -- 查看控制台错误信息 -- 检查文件语法 -- 验证导入路径 -- 确认类型定义 - -#### **2. 运行时错误排查** - -- 检查页面配置 -- 验证组件 Props -- 确认事件处理 -- 测试页面跳转 - -#### **3. 性能优化** - -- 合理使用响应式数据 -- 避免不必要的计算属性 -- 优化组件渲染 -- 使用合适的生命周期 - -#### **4. .uvue文件特殊处理** - -- 保持模板结构简单,避免过度复杂 -- 使用UTS编译器兼容的字符集 -- 定期检查文件编码和特殊字符 -- 采用渐进式开发策略,从简单到复杂 -- 出现编译错误时优先简化模板结构 - -#### **5. AdminLayout组件维护** - -- 保持组件结构简单,避免过度复杂的功能 -- 使用正确的文件扩展名(.uvue)在导入路径中 -- 定期验证组件的导出和解析 -- 出现解析错误时优先简化组件结构 -- 确保组件语法符合UTS编译器要求 - -#### **6. 双侧边栏布局设计** - -- 主侧边栏只显示一级菜单图标,保持简洁 -- 内容侧边栏显示二级菜单,位于内容区左侧 -- 合理分配侧边栏宽度,确保移动端兼容性 -- 使用计算属性动态控制侧边栏显示 -- 确保路由同步和高亮状态正确 - -## 📚 参考资源 - -### **官方文档** - -- [uni-app-x 官方文档](https://doc.dcloud.net.cn/uni-app-x/) -- [Vue 3 组合式 API](https://cn.vuejs.org/guide/extras/composition-api-faq.html) -- [TypeScript 指南](https://www.typescriptlang.org/docs/) - -### **最佳实践** - -- 遵循项目现有的代码风格 -- 保持配置的一致性 -- 定期检查和更新依赖 -- 编写清晰的注释 - ---- - -## 🎯 总结 - -通过本次修复,我们建立了完整的 uni-app-x 项目开发和调试方法论: - -1. **问题定位**: 快速识别配置和语法错误 -2. **逐步修复**: 从简单到复杂,逐步解决问题 -3. **规范建立**: 统一的代码和配置规范 -4. **最佳实践**: 可复用的开发模式 - -### **新增问题类型** - -#### **特殊字符兼容性问题** - -- **现象**: `[plugin:uts] Invalid end tag` 错误 -- **原因**: emoji 字符或特殊 Unicode 符号导致模板解析失败 -- **解决方案**: 替换为标准 ASCII 字符或安全 Unicode 符号 -- **预防**: 在模板中使用经过验证的安全字符集 - ---- - -#### **原因十四:AdminLayout代码清理不完整** - -- **遗留变量引用**: 移除功能后仍引用已删除的变量 -- **计算属性缺失**: 重构时遗漏必要的计算属性 -- **模板依赖问题**: 模板中使用未定义的响应式属性 - ---- - -这个指南现在涵盖了 uni-app-x 项目开发中最常见的 14 类编译和运行时错误,为后续开发提供了完整的故障排除和最佳实践指导。 🚀 diff --git a/layouts/admin/router/adminComponentMap.uts b/layouts/admin/router/adminComponentMap.uts index e1549903..26034adf 100644 --- a/layouts/admin/router/adminComponentMap.uts +++ b/layouts/admin/router/adminComponentMap.uts @@ -24,15 +24,12 @@ import UserLevel from '@/pages/mall/admin/user/level.uvue' import UserGroup from '@/pages/mall/admin/user/group.uvue' import UserLabel from '@/pages/mall/admin/user/label.uvue' import MemberConfig from '@/pages/mall/admin/user/MemberConfig.uvue' -// 其他用户模块组件暂时使用 PlaceholderPage -// import UserGradeType from '@/pages/mall/admin/user/grade/type.uvue' -// import UserGradeCard from '@/pages/mall/admin/user/grade/card.uvue' -// import UserGradeRecord from '@/pages/mall/admin/user/grade/record.uvue' -// import UserGradeRight from '@/pages/mall/admin/user/grade/right.uvue' -// import UserMemberConfig from '@/pages/mall/admin/user/MemberConfig.uvue' // 导入商品模块(纯组件,不包含 AdminLayout) -import ProductList from '@/pages/mall/admin/product/list.uvue' +import ProductStatistic from '@/pages/mall/admin/product/product-statistics/index.uvue' +import ProductList from '@/pages/mall/admin/product/product-management/index.uvue' +import ProductEdit from '@/pages/mall/admin/product/product-management/edit.uvue' +import ProductMemberPrice from '@/pages/mall/admin/product/product-management/member-price.uvue' import ProductClassify from '@/pages/mall/admin/product/classify.uvue' import ProductReply from '@/pages/mall/admin/product/reply.uvue' import ProductAttr from '@/pages/mall/admin/product/attr.uvue' @@ -48,16 +45,39 @@ import OrderCashier from '@/pages/mall/admin/order/cashier-order/index.uvue' import OrderVerify from '@/pages/mall/admin/order/write-off-records/index.uvue' import OrderConfig from '@/pages/mall/admin/order/order-configuration/index.uvue' -// 营销、内容、财务、数据、设置模块暂时使用 PlaceholderPage +// 营销设置模块暂时使用 PlaceholderPage // 避免循环依赖问题 -// import MarketingCoupon from '@/pages/mall/admin/marketing/coupon/list.uvue' -// import MarketingIntegral from '@/pages/mall/admin/marketing/integral/list.uvue' -// import MarketingBargain from '@/pages/mall/admin/marketing/bargain/list.uvue' -// import MarketingCombination from '@/pages/mall/admin/marketing/combination/list.uvue' -// import MarketingSeckill from '@/pages/mall/admin/marketing/seckill/list.uvue' -// import CmsArticle from '@/pages/mall/admin/cms/article/list.uvue' -// import CmsCategory from '@/pages/mall/admin/cms/category/list.uvue' -// import FinanceRecord from '@/pages/mall/admin/finance/record.uvue' +import CmsArticle from '@/pages/mall/admin/cms/article/list.uvue' +import CmsCategory from '@/pages/mall/admin/cms/category/list.uvue' +import MarketingCouponList from '@/pages/mall/admin/marketing/coupon/list.uvue' +import MarketingCouponUser from '@/pages/mall/admin/marketing/coupon/user.uvue' +import MarketingIntegralStatistic from '@/pages/mall/admin/marketing/integral/statistic.uvue' + +// 导入财务模块(纯组件) +import FinanceTransactionStats from '@/pages/mall/admin/finance/transaction_stats.uvue' +import FinanceWithdrawal from '@/pages/mall/admin/finance/withdrawal.uvue' +import FinanceInvoice from '@/pages/mall/admin/finance/invoice.uvue' +import FinanceRecharge from '@/pages/mall/admin/finance/recharge.uvue' +import FinanceCapitalFlow from '@/pages/mall/admin/finance/capital_flow.uvue' +import FinanceBill from '@/pages/mall/admin/finance/bill.uvue' +import FinanceCommission from '@/pages/mall/admin/finance/commission.uvue' +import FinanceBalanceStats from '@/pages/mall/admin/finance/balance_stats.uvue' +import FinanceBalanceRecord from '@/pages/mall/admin/finance/balance_record.uvue' + +// 导入客服模块 +import KefuList from '@/pages/mall/admin/kefu/list.uvue' +import KefuWords from '@/pages/mall/admin/kefu/words.uvue' +import KefuFeedback from '@/pages/mall/admin/kefu/feedback.uvue' +import KefuConfig from '@/pages/mall/admin/kefu/config.uvue' + +// 导入装修模块 +import DecorationHome from '@/pages/mall/admin/decoration/home.uvue' +import DecorationCategory from '@/pages/mall/admin/decoration/category.uvue' +import DecorationUser from '@/pages/mall/admin/decoration/user.uvue' + +// 导入维护模块 +import MaintainDevConfig from '@/pages/mall/admin/maintain/dev/config.uvue' + // import StatisticIndex from '@/pages/mall/admin/statistic/index.uvue' // import SettingSystemConfig from '@/pages/mall/admin/setting/system/config.uvue' // import SettingSystemAdmin from '@/pages/mall/admin/setting/system/admin.uvue' @@ -77,13 +97,12 @@ export const componentMap: Map = new Map([ ['UserGroup', UserGroup], ['UserLabel', UserLabel], ['UserMemberConfig', MemberConfig], - ['UserGradeType', PlaceholderPage], // 暂时使用占位组件 - ['UserGradeCard', PlaceholderPage], - ['UserGradeRecord', PlaceholderPage], - ['UserGradeRight', PlaceholderPage], // 商品模块 + ['ProductStatistic', ProductStatistic], ['ProductList', ProductList], + ['ProductEdit', ProductEdit], + ['ProductMemberPrice', ProductMemberPrice], ['ProductClassify', ProductClassify], ['ProductReply', ProductReply], ['ProductAttr', ProductAttr], @@ -99,19 +118,62 @@ export const componentMap: Map = new Map([ ['OrderVerify', OrderVerify], ['OrderConfig', OrderConfig], - // 营销模块 - 暂时使用占位组件 - ['MarketingCoupon', PlaceholderPage], - ['MarketingIntegral', PlaceholderPage], - ['MarketingBargain', PlaceholderPage], - ['MarketingCombination', PlaceholderPage], - ['MarketingSeckill', PlaceholderPage], + // 营销模块 + // 1. 优惠券 + ['MarketingCouponList', MarketingCouponList], + ['MarketingCouponUser', MarketingCouponUser], + // 2. 积分管理 + ['MarketingIntegralStatistic', MarketingIntegralStatistic], + ['MarketingIntegralProduct', PlaceholderPage], + ['MarketingIntegralOrder', PlaceholderPage], + ['MarketingIntegralRecord', PlaceholderPage], + // 3. 抽奖管理 + ['MarketingLotteryList', PlaceholderPage], + ['MarketingLotteryConfig', PlaceholderPage], + // 4. 砍价管理 + ['MarketingBargainProduct', PlaceholderPage], + ['MarketingBargainList', PlaceholderPage], + // 5. 拼团管理 + ['MarketingCombinationProduct', PlaceholderPage], + ['MarketingCombinationList', PlaceholderPage], + // 6. 秒杀管理 + ['MarketingSeckillList', PlaceholderPage], + ['MarketingSeckillProduct', PlaceholderPage], + ['MarketingSeckillConfig', PlaceholderPage], + // 7. 付费会员 + ['MarketingMemberType', PlaceholderPage], + ['MarketingMemberRight', PlaceholderPage], + ['MarketingMemberCard', PlaceholderPage], + ['MarketingMemberRecord', PlaceholderPage], + ['MarketingMemberConfig', PlaceholderPage], + // 8. 直播管理 + ['MarketingLiveRoom', PlaceholderPage], + ['MarketingLiveProduct', PlaceholderPage], + ['MarketingLiveAnchor', PlaceholderPage], + // 9. 用户充值 + ['MarketingRechargeQuota', PlaceholderPage], + ['MarketingRechargeConfig', PlaceholderPage], + // 10. 每日签到 + ['MarketingCheckinConfig', PlaceholderPage], + ['MarketingCheckinReward', PlaceholderPage], + // 11. 渠道码 & 新人礼 + ['MarketingChannelList', PlaceholderPage], + ['MarketingNewcomerGift', PlaceholderPage], - // 内容模块 - 暂时使用占位组件 - ['CmsArticle', PlaceholderPage], - ['CmsCategory', PlaceholderPage], + // 内容模块 + ['CmsArticle', CmsArticle], + ['CmsCategory', CmsCategory], - // 财务模块 - 暂时使用占位组件 - ['FinanceRecord', PlaceholderPage], + // 财务模块 + ['FinanceTransactionStats', FinanceTransactionStats], + ['FinanceWithdrawal', FinanceWithdrawal], + ['FinanceInvoice', FinanceInvoice], + ['FinanceRecharge', FinanceRecharge], + ['FinanceCapitalFlow', FinanceCapitalFlow], + ['FinanceBill', FinanceBill], + ['FinanceCommission', FinanceCommission], + ['FinanceBalanceStats', FinanceBalanceStats], + ['FinanceBalanceRecord', FinanceBalanceRecord], // 数据模块 - 暂时使用占位组件 ['StatisticIndex', PlaceholderPage], @@ -119,7 +181,56 @@ export const componentMap: Map = new Map([ // 设置模块 - 暂时使用占位组件 ['SettingSystemConfig', PlaceholderPage], ['SettingSystemAdmin', PlaceholderPage], - ['SettingSystemRole', PlaceholderPage] + ['SettingSystemRole', PlaceholderPage], + + // 分销模块 + ['DistributionStatistic', PlaceholderPage], + ['DistributionList', PlaceholderPage], + ['DistributionConfig', PlaceholderPage], + + // 客服模块 + ['KefuList', KefuList], + ['KefuWords', KefuWords], + ['KefuFeedback', KefuFeedback], + ['KefuAutoReply', PlaceholderPage], + ['KefuConfig', KefuConfig], + + // 装修模块 + ['DecorationHome', DecorationHome], + ['DecorationCategory', DecorationCategory], + ['DecorationUser', DecorationUser], + ['DecorationData', PlaceholderPage], + ['DecorationStyle', PlaceholderPage], + ['DecorationMaterial', PlaceholderPage], + ['DecorationLink', PlaceholderPage], + + // 应用模块 + ['AppStatistic', PlaceholderPage], + ['AppList', PlaceholderPage], + + // 维护模块 + ['MaintainDevConfig', MaintainDevConfig], + ['MaintainDevData', PlaceholderPage], + ['MaintainDevTask', PlaceholderPage], + ['MaintainDevAuth', PlaceholderPage], + ['MaintainDevModule', PlaceholderPage], + ['MaintainDevEvent', PlaceholderPage], + ['MaintainSecurityCache', PlaceholderPage], + ['MaintainSecurityLog', PlaceholderPage], + ['MaintainSecurityUpgrade', PlaceholderPage], + ['MaintainDataLogistics', PlaceholderPage], + ['MaintainDataCity', PlaceholderPage], + ['MaintainDataClear', PlaceholderPage], + ['MaintainApiAccount', PlaceholderPage], + ['MaintainLangList', PlaceholderPage], + ['MaintainLangDetail', PlaceholderPage], + ['MaintainLangRegion', PlaceholderPage], + ['MaintainLangConfig', PlaceholderPage], + ['MaintainToolDb', PlaceholderPage], + ['MaintainToolFile', PlaceholderPage], + ['MaintainToolApi', PlaceholderPage], + ['MaintainToolDic', PlaceholderPage], + ['MaintainSysInfo', PlaceholderPage] ]) /** diff --git a/layouts/admin/router/adminRoutes.uts b/layouts/admin/router/adminRoutes.uts index c782323f..f48e12db 100644 --- a/layouts/admin/router/adminRoutes.uts +++ b/layouts/admin/router/adminRoutes.uts @@ -72,18 +72,7 @@ export const topMenus: TopMenu[] = [ path: '/pages/mall/admin/user/list', order: 2, groups: [ - { id: 'user-manage', title: '', order: 1 }, - { id: 'member-manage', title: '会员管理', order: 2 } - ] - }, - { - id: 'product', - title: '商品', - icon: 'product', - path: '/pages/mall/admin/product/list', - order: 3, - groups: [ - { id: 'product-manage', title: '商品管理', order: 1 } + { id: 'user-manage', title: '', order: 1 } ] }, { @@ -91,11 +80,21 @@ export const topMenus: TopMenu[] = [ title: '订单', icon: 'order', path: '/pages/mall/admin/order/list', - order: 4, + order: 3, groups: [ { id: 'order-manage', title: '', order: 1 } ] }, + { + id: 'product', + title: '商品', + icon: 'product', + path: '/pages/mall/admin/product/statistic', + order: 4, + groups: [ + { id: 'product-manage', title: '商品管理', order: 1 } + ] + }, { id: 'marketing', title: '营销', @@ -103,8 +102,51 @@ export const topMenus: TopMenu[] = [ path: '/pages/mall/admin/marketing/coupon/list', order: 5, groups: [ - { id: 'marketing-tool', title: '营销工具', order: 1 }, - { id: 'marketing-activity', title: '营销活动', order: 2 } + { id: 'marketing-coupon', title: '优惠券', order: 1 }, + { id: 'marketing-integral', title: '积分管理', order: 2 }, + { id: 'marketing-lottery', title: '抽奖管理', order: 3 }, + { id: 'marketing-bargain', title: '砍价管理', order: 4 }, + { id: 'marketing-combination', title: '拼团管理', order: 5 }, + { id: 'marketing-seckill', title: '秒杀管理', order: 6 }, + { id: 'marketing-member', title: '付费会员', order: 7 }, + { id: 'marketing-live', title: '直播管理', order: 8 }, + { id: 'marketing-recharge', title: '用户充值', order: 9 }, + { id: 'marketing-checkin', title: '每日签到', order: 10 }, + { id: 'marketing-other', title: '其他', order: 11 } + ] + }, + { + id: 'distribution', + title: '分销', + icon: 'share', + path: '/pages/mall/admin/distribution/statistic', + order: 6, + groups: [ + { id: 'distribution-manage', title: '', order: 1 } + ] + }, + { + id: 'kefu', + title: '客服', + icon: 'customer-service', + path: '/pages/mall/admin/kefu/list', + order: 7, + groups: [ + { id: 'kefu-manage', title: '', order: 1 } + ] + }, + { + id: 'finance', + title: '财务', + icon: 'finance', + path: '/pages/mall/admin/finance/transaction_stats', + order: 8, + groups: [ + { id: 'finance-data', title: '', order: 1 }, + { id: 'finance-ops', title: '财务操作', order: 2 }, + { id: 'finance-record', title: '财务记录', order: 3 }, + { id: 'finance-commission', title: '佣金记录', order: 4 }, + { id: 'finance-balance', title: '余额记录', order: 5 } ] }, { @@ -112,29 +154,29 @@ export const topMenus: TopMenu[] = [ title: '内容', icon: 'content', path: '/pages/mall/admin/cms/article/list', - order: 6, + order: 9, groups: [ { id: 'cms-manage', title: '内容管理', order: 1 } ] }, { - id: 'finance', - title: '财务', - icon: 'finance', - path: '/pages/mall/admin/finance/record', - order: 7, + id: 'decoration', + title: '装修', + icon: 'decoration', + path: '/pages/mall/admin/decoration/home', + order: 10, groups: [ - { id: 'finance-manage', title: '财务管理', order: 1 } + { id: 'decoration-manage', title: '', order: 1 } ] }, { - id: 'statistic', - title: '数据', - icon: 'statistic', - path: '/pages/mall/admin/statistic/index', - order: 8, + id: 'app', + title: '应用', + icon: 'app', + path: '/pages/mall/admin/app/statistic', + order: 11, groups: [ - { id: 'statistic-data', title: '数据统计', order: 1 } + { id: 'app-manage', title: '', order: 1 } ] }, { @@ -142,11 +184,26 @@ export const topMenus: TopMenu[] = [ title: '设置', icon: 'setting', path: '/pages/mall/admin/setting/system/config', - order: 9, + order: 12, groups: [ { id: 'setting-system', title: '系统设置', order: 1 }, - { id: 'setting-application', title: '应用设置', order: 2 }, - { id: 'setting-maintain', title: '维护管理', order: 3 } + { id: 'setting-application', title: '应用设置', order: 2 } + ] + }, + { + id: 'maintain', + title: '维护', + icon: 'tool', + path: '/pages/mall/admin/maintain/dev/config', + order: 13, + groups: [ + { id: 'maintain-dev', title: '开发配置', order: 1 }, + { id: 'maintain-security', title: '安全维护', order: 2 }, + { id: 'maintain-data', title: '数据维护', order: 3 }, + { id: 'maintain-api', title: '对外接口', order: 4 }, + { id: 'maintain-lang', title: '语言设置', order: 5 }, + { id: 'maintain-tool', title: '开发工具', order: 6 }, + { id: 'maintain-sys', title: '系统信息', order: 7 } ] } ] @@ -218,58 +275,18 @@ export const routes: RouteRecord[] = [ auth: ['user-user-level'], order: 5 }, - { - id: 'user_member_config', - title: '用户配置', - path: '/pages/mall/admin/user/MemberConfig', - componentKey: 'UserMemberConfig', - parentId: 'user', - groupId: 'user-manage', - auth: ['admin-user-member-config'], - order: 6 - }, - { - id: 'user_type', - title: '会员类型', - path: '/pages/mall/admin/user/grade/type', - componentKey: 'UserGradeType', - parentId: 'user', - groupId: 'member-manage', - auth: ['admin-user-member-type'], - order: 1 - }, - { - id: 'user_card', - title: '卡密会员', - path: '/pages/mall/admin/user/grade/card', - componentKey: 'UserGradeCard', - parentId: 'user', - groupId: 'member-manage', - auth: ['admin-user-grade-card'], - order: 2 - }, - { - id: 'user_record', - title: '会员记录', - path: '/pages/mall/admin/user/grade/record', - componentKey: 'UserGradeRecord', - parentId: 'user', - groupId: 'member-manage', - auth: ['admin-user-grade-record'], - order: 3 - }, - { - id: 'user_right', - title: '会员权益', - path: '/pages/mall/admin/user/grade/right', - componentKey: 'UserGradeRight', - parentId: 'user', - groupId: 'member-manage', - auth: ['admin-user-grade-right'], - order: 4 - }, // ========== 商品模块 ========== + { + id: 'product_statistic', + title: '商品统计', + path: '/pages/mall/admin/product/statistic', + componentKey: 'ProductStatistic', + parentId: 'product', + groupId: 'product-manage', + auth: ['admin-store-storeProuduct-statistic'], + order: 1 + }, { id: 'product_productList', title: '商品管理', @@ -279,7 +296,7 @@ export const routes: RouteRecord[] = [ groupId: 'product-manage', auth: ['admin-store-storeProuduct-index'], keepAlive: true, - order: 1 + order: 2 }, { id: 'product_productClassify', @@ -289,16 +306,6 @@ export const routes: RouteRecord[] = [ parentId: 'product', groupId: 'product-manage', auth: ['admin-store-storeCategory-index'], - order: 2 - }, - { - id: 'product_productEvaluate', - title: '商品评论', - path: '/pages/mall/admin/product/reply', - componentKey: 'ProductReply', - parentId: 'product', - groupId: 'product-manage', - auth: ['admin-store-storeProuduct-index'], order: 3 }, { @@ -341,6 +348,36 @@ export const routes: RouteRecord[] = [ auth: ['admin-product-protection-list'], order: 7 }, + { + id: 'product_productEvaluate', + title: '商品评论', + path: '/pages/mall/admin/product/reply', + componentKey: 'ProductReply', + parentId: 'product', + groupId: 'product-manage', + auth: ['admin-store-storeProuduct-index'], + order: 8 + }, + { + id: 'product_edit', + title: '编辑商品', + path: '/pages/mall/admin/product/edit', + componentKey: 'ProductEdit', + parentId: 'product', + groupId: 'product-manage', + hidden: true, + auth: ['admin-store-storeProuduct-index'] + }, + { + id: 'product_member_price', + title: '预售会员价', + path: '/pages/mall/admin/product/member-price', + componentKey: 'ProductMemberPrice', + parentId: 'product', + groupId: 'product-manage', + hidden: true, + auth: ['admin-store-storeProuduct-index'] + }, // ========== 订单模块 ========== { @@ -406,56 +443,307 @@ export const routes: RouteRecord[] = [ }, // ========== 营销模块 ========== + // 1. 优惠券 { - id: 'marketing_coupon', - title: '优惠券', + id: 'marketing_coupon_list', + title: '优惠券列表', path: '/pages/mall/admin/marketing/coupon/list', - componentKey: 'MarketingCoupon', + componentKey: 'MarketingCouponList', parentId: 'marketing', - groupId: 'marketing-tool', + groupId: 'marketing-coupon', auth: ['admin-marketing-storeCoupon-index'], order: 1 }, { - id: 'marketing_integral', - title: '积分管理', - path: '/pages/mall/admin/marketing/integral/list', - componentKey: 'MarketingIntegral', + id: 'marketing_coupon_user', + title: '用户领取记录', + path: '/pages/mall/admin/marketing/coupon/user', + componentKey: 'MarketingCouponUser', parentId: 'marketing', - groupId: 'marketing-tool', - auth: ['admin-marketing-storeIntegral-index'], + groupId: 'marketing-coupon', + auth: ['admin-marketing-storeCouponUser-index'], + order: 2 + }, + // 2. 积分管理 + { + id: 'marketing_integral_statistic', + title: '积分统计', + path: '/pages/mall/admin/marketing/integral/statistic', + componentKey: 'MarketingIntegralStatistic', + parentId: 'marketing', + groupId: 'marketing-integral', + auth: ['admin-marketing-integral-statistic'], + order: 1 + }, + { + id: 'marketing_integral_product', + title: '积分商品', + path: '/pages/mall/admin/marketing/integral/product', + componentKey: 'MarketingIntegralProduct', + parentId: 'marketing', + groupId: 'marketing-integral', + auth: ['admin-marketing-integral-product'], order: 2 }, { - id: 'marketing_bargain', - title: '砍价活动', - path: '/pages/mall/admin/marketing/bargain/list', - componentKey: 'MarketingBargain', + id: 'marketing_integral_order', + title: '积分订单', + path: '/pages/mall/admin/marketing/integral/order', + componentKey: 'MarketingIntegralOrder', parentId: 'marketing', - groupId: 'marketing-activity', - auth: ['admin-marketing-storeBargain-index'], + groupId: 'marketing-integral', + auth: ['admin-marketing-integral-order'], order: 3 }, { - id: 'marketing_combination', - title: '拼团活动', - path: '/pages/mall/admin/marketing/combination/list', - componentKey: 'MarketingCombination', + id: 'marketing_integral_record', + title: '积分记录', + path: '/pages/mall/admin/marketing/integral/record', + componentKey: 'MarketingIntegralRecord', parentId: 'marketing', - groupId: 'marketing-activity', - auth: ['admin-marketing-storeCombination-index'], + groupId: 'marketing-integral', + auth: ['admin-marketing-integral-record'], + order: 4 + }, + // 3. 抽奖管理 + { + id: 'marketing_lottery_list', + title: '抽奖列表', + path: '/pages/mall/admin/marketing/lottery/list', + componentKey: 'MarketingLotteryList', + parentId: 'marketing', + groupId: 'marketing-lottery', + auth: ['admin-marketing-lottery-index'], + order: 1 + }, + { + id: 'marketing_lottery_config', + title: '抽奖配置', + path: '/pages/mall/admin/marketing/lottery/config', + componentKey: 'MarketingLotteryConfig', + parentId: 'marketing', + groupId: 'marketing-lottery', + auth: ['admin-marketing-lottery-config'], + order: 2 + }, + // 4. 砍价管理 + { + id: 'marketing_bargain_product', + title: '砍价商品', + path: '/pages/mall/admin/marketing/bargain/product', + componentKey: 'MarketingBargainProduct', + parentId: 'marketing', + groupId: 'marketing-bargain', + auth: ['admin-marketing-bargain-product'], + order: 1 + }, + { + id: 'marketing_bargain_list', + title: '砍价列表', + path: '/pages/mall/admin/marketing/bargain/list', + componentKey: 'MarketingBargainList', + parentId: 'marketing', + groupId: 'marketing-bargain', + auth: ['admin-marketing-bargain-index'], + order: 2 + }, + // 5. 拼团管理 + { + id: 'marketing_combination_product', + title: '拼团商品', + path: '/pages/mall/admin/marketing/combination/product', + componentKey: 'MarketingCombinationProduct', + parentId: 'marketing', + groupId: 'marketing-combination', + auth: ['admin-marketing-combination-product'], + order: 1 + }, + { + id: 'marketing_combination_list', + title: '拼团列表', + path: '/pages/mall/admin/marketing/combination/list', + componentKey: 'MarketingCombinationList', + parentId: 'marketing', + groupId: 'marketing-combination', + auth: ['admin-marketing-combination-index'], + order: 2 + }, + // 6. 秒杀管理 + { + id: 'marketing_seckill_list', + title: '秒杀列表', + path: '/pages/mall/admin/marketing/seckill/list', + componentKey: 'MarketingSeckillList', + parentId: 'marketing', + groupId: 'marketing-seckill', + auth: ['admin-marketing-seckill-index'], + order: 1 + }, + { + id: 'marketing_seckill_product', + title: '秒杀商品', + path: '/pages/mall/admin/marketing/seckill/product', + componentKey: 'MarketingSeckillProduct', + parentId: 'marketing', + groupId: 'marketing-seckill', + auth: ['admin-marketing-seckill-product'], + order: 2 + }, + { + id: 'marketing_seckill_config', + title: '秒杀配置', + path: '/pages/mall/admin/marketing/seckill/config', + componentKey: 'MarketingSeckillConfig', + parentId: 'marketing', + groupId: 'marketing-seckill', + auth: ['admin-marketing-seckill-config'], + order: 3 + }, + // 7. 付费会员 (从用户模块迁入) + { + id: 'marketing_member_type', + title: '会员类型', + path: '/pages/mall/admin/marketing/member/type', + componentKey: 'MarketingMemberType', + parentId: 'marketing', + groupId: 'marketing-member', + auth: ['admin-user-member-type'], + order: 1 + }, + { + id: 'marketing_member_right', + title: '会员权益', + path: '/pages/mall/admin/marketing/member/right', + componentKey: 'MarketingMemberRight', + parentId: 'marketing', + groupId: 'marketing-member', + auth: ['admin-user-member-right'], + order: 2 + }, + { + id: 'marketing_member_card', + title: '卡密会员', + path: '/pages/mall/admin/marketing/member/card', + componentKey: 'MarketingMemberCard', + parentId: 'marketing', + groupId: 'marketing-member', + auth: ['admin-user-member-card'], + order: 3 + }, + { + id: 'marketing_member_record', + title: '会员记录', + path: '/pages/mall/admin/marketing/member/record', + componentKey: 'MarketingMemberRecord', + parentId: 'marketing', + groupId: 'marketing-member', + auth: ['admin-user-member-record'], order: 4 }, { - id: 'marketing_seckill', - title: '秒杀活动', - path: '/pages/mall/admin/marketing/seckill/list', - componentKey: 'MarketingSeckill', + id: 'marketing_member_config', + title: '会员配置', + path: '/pages/mall/admin/marketing/member/config', + componentKey: 'MarketingMemberConfig', parentId: 'marketing', - groupId: 'marketing-activity', - auth: ['admin-marketing-storeSeckill-index'], + groupId: 'marketing-member', + auth: ['admin-user-member-config'], order: 5 }, + // 8. 直播管理 + { + id: 'marketing_live_room', + title: '直播间管理', + path: '/pages/mall/admin/marketing/live/room', + componentKey: 'MarketingLiveRoom', + parentId: 'marketing', + groupId: 'marketing-live', + auth: ['admin-marketing-live-room'], + order: 1 + }, + { + id: 'marketing_live_product', + title: '直播商品管理', + path: '/pages/mall/admin/marketing/live/product', + componentKey: 'MarketingLiveProduct', + parentId: 'marketing', + groupId: 'marketing-live', + auth: ['admin-marketing-live-product'], + order: 2 + }, + { + id: 'marketing_live_anchor', + title: '主播管理', + path: '/pages/mall/admin/marketing/live/anchor', + componentKey: 'MarketingLiveAnchor', + parentId: 'marketing', + groupId: 'marketing-live', + auth: ['admin-marketing-live-anchor'], + order: 3 + }, + // 9. 用户充值 + { + id: 'marketing_recharge_quota', + title: '金额设置', + path: '/pages/mall/admin/marketing/recharge/quota', + componentKey: 'MarketingRechargeQuota', + parentId: 'marketing', + groupId: 'marketing-recharge', + auth: ['admin-marketing-recharge-quota'], + order: 1 + }, + { + id: 'marketing_recharge_config', + title: '充值配置', + path: '/pages/mall/admin/marketing/recharge/config', + componentKey: 'MarketingRechargeConfig', + parentId: 'marketing', + groupId: 'marketing-recharge', + auth: ['admin-marketing-recharge-config'], + order: 2 + }, + // 10. 每日签到 + { + id: 'marketing_checkin_config', + title: '签到配置', + path: '/pages/mall/admin/marketing/checkin/config', + componentKey: 'MarketingCheckinConfig', + parentId: 'marketing', + groupId: 'marketing-checkin', + auth: ['admin-marketing-checkin-config'], + order: 1 + }, + { + id: 'marketing_checkin_reward', + title: '签到奖励', + path: '/pages/mall/admin/marketing/checkin/reward', + componentKey: 'MarketingCheckinReward', + parentId: 'marketing', + groupId: 'marketing-checkin', + auth: ['admin-marketing-checkin-reward'], + order: 2 + }, + // 11. 渠道码 & 新人礼 + { + id: 'marketing_channel_code', + title: '渠道码', + path: '/pages/mall/admin/marketing/channel/list', + componentKey: 'MarketingChannelList', + parentId: 'marketing', + groupId: 'marketing-other', + auth: ['admin-marketing-channel-index'], + order: 1 + }, + { + id: 'marketing_newcomer_gift', + title: '新人礼', + path: '/pages/mall/admin/marketing/newcomer/gift', + componentKey: 'MarketingNewcomerGift', + parentId: 'marketing', + groupId: 'marketing-other', + auth: ['admin-marketing-newcomer-index'], + order: 2 + }, // ========== 内容模块 ========== { @@ -481,15 +769,95 @@ export const routes: RouteRecord[] = [ // ========== 财务模块 ========== { - id: 'finance_record', - title: '财务记录', - path: '/pages/mall/admin/finance/record', - componentKey: 'FinanceRecord', + id: 'finance_transaction_stats', + title: '交易统计', + path: '/pages/mall/admin/finance/transaction_stats', + componentKey: 'FinanceTransactionStats', parentId: 'finance', - groupId: 'finance-manage', - auth: ['admin-finance-record-index'], + groupId: 'finance-data', + auth: ['admin-finance-transaction-stats'], order: 1 }, + { + id: 'finance_withdrawal', + title: '提现申请', + path: '/pages/mall/admin/finance/withdrawal', + componentKey: 'FinanceWithdrawal', + parentId: 'finance', + groupId: 'finance-ops', + auth: ['admin-finance-withdrawal-index'], + order: 1 + }, + { + id: 'finance_invoice', + title: '发票管理', + path: '/pages/mall/admin/finance/invoice', + componentKey: 'FinanceInvoice', + parentId: 'finance', + groupId: 'finance-ops', + auth: ['admin-finance-invoice-index'], + order: 2 + }, + { + id: 'finance_recharge', + title: '充值记录', + path: '/pages/mall/admin/finance/recharge', + componentKey: 'FinanceRecharge', + parentId: 'finance', + groupId: 'finance-record', + auth: ['admin-finance-recharge-index'], + order: 1 + }, + { + id: 'finance_capital_flow', + title: '资金流水', + path: '/pages/mall/admin/finance/capital_flow', + componentKey: 'FinanceCapitalFlow', + parentId: 'finance', + groupId: 'finance-record', + auth: ['admin-finance-capital-flow-index'], + order: 2 + }, + { + id: 'finance_bill', + title: '账单记录', + path: '/pages/mall/admin/finance/bill', + componentKey: 'FinanceBill', + parentId: 'finance', + groupId: 'finance-record', + auth: ['admin-finance-bill-index'], + order: 3 + }, + { + id: 'finance_commission_record', + title: '佣金记录', + path: '/pages/mall/admin/finance/commission', + componentKey: 'FinanceCommission', + parentId: 'finance', + groupId: 'finance-commission', + auth: ['admin-finance-commission-index'], + order: 1 + }, + { + id: 'finance_balance_stats', + title: '余额统计', + path: '/pages/mall/admin/finance/balance_stats', + componentKey: 'FinanceBalanceStats', + parentId: 'finance', + groupId: 'finance-balance', + auth: ['admin-finance-balance-stats'], + order: 1 + }, + { + id: 'finance_balance_record', + title: '余额记录', + path: '/pages/mall/admin/finance/balance_record', + componentKey: 'FinanceBalanceRecord', + parentId: 'finance', + groupId: 'finance-balance', + auth: ['admin-finance-balance-record-index'], + order: 2 + }, // ========== 数据统计模块 ========== { @@ -533,7 +901,205 @@ export const routes: RouteRecord[] = [ groupId: 'setting-system', auth: ['admin-setting-system-role'], order: 3 - } + }, + + // ========== 分销模块 ========== + { + id: 'distribution_statistic', + title: '分销统计', + path: '/pages/mall/admin/distribution/statistic', + componentKey: 'DistributionStatistic', + parentId: 'distribution', + groupId: 'distribution-manage', + order: 1 + }, + { + id: 'distribution_list', + title: '分销员列表', + path: '/pages/mall/admin/distribution/list', + componentKey: 'DistributionList', + parentId: 'distribution', + groupId: 'distribution-manage', + order: 2 + }, + { + id: 'distribution_config', + title: '分销设置', + path: '/pages/mall/admin/distribution/config', + componentKey: 'DistributionConfig', + parentId: 'distribution', + groupId: 'distribution-manage', + order: 3 + }, + + // ========== 客服模块 ========== + { + id: 'kefu_list', + title: '客服列表', + path: '/pages/mall/admin/kefu/list', + componentKey: 'KefuList', + parentId: 'kefu', + groupId: 'kefu-manage', + order: 1 + }, + { + id: 'kefu_words', + title: '客服话术', + path: '/pages/mall/admin/kefu/words', + componentKey: 'KefuWords', + parentId: 'kefu', + groupId: 'kefu-manage', + order: 2 + }, + { + id: 'kefu_feedback', + title: '用户留言', + path: '/pages/mall/admin/kefu/feedback', + componentKey: 'KefuFeedback', + parentId: 'kefu', + groupId: 'kefu-manage', + order: 3 + }, + { + id: 'kefu_auto_reply', + title: '自动回复', + path: '/pages/mall/admin/kefu/auto_reply', + componentKey: 'KefuAutoReply', + parentId: 'kefu', + groupId: 'kefu-manage', + order: 4 + }, + { + id: 'kefu_config', + title: '客服配置', + path: '/pages/mall/admin/kefu/config', + componentKey: 'KefuConfig', + parentId: 'kefu', + groupId: 'kefu-manage', + order: 5 + }, + + // ========== 装修模块 ========== + { + id: 'decoration_home', + title: '首页装修', + path: '/pages/mall/admin/decoration/home', + componentKey: 'DecorationHome', + parentId: 'decoration', + groupId: 'decoration-manage', + order: 1 + }, + { + id: 'decoration_category', + title: '商品分类', + path: '/pages/mall/admin/decoration/category', + componentKey: 'DecorationCategory', + parentId: 'decoration', + groupId: 'decoration-manage', + order: 2 + }, + { + id: 'decoration_user', + title: '个人中心', + path: '/pages/mall/admin/decoration/user', + componentKey: 'DecorationUser', + parentId: 'decoration', + groupId: 'decoration-manage', + order: 3 + }, + { + id: 'decoration_data', + title: '数据配置', + path: '/pages/mall/admin/decoration/data', + componentKey: 'DecorationData', + parentId: 'decoration', + groupId: 'decoration-manage', + order: 4 + }, + { + id: 'decoration_style', + title: '主题风格', + path: '/pages/mall/admin/decoration/style', + componentKey: 'DecorationStyle', + parentId: 'decoration', + groupId: 'decoration-manage', + order: 5 + }, + { + id: 'decoration_material', + title: '素材管理', + path: '/pages/mall/admin/decoration/material', + componentKey: 'DecorationMaterial', + parentId: 'decoration', + groupId: 'decoration-manage', + order: 6 + }, + { + id: 'decoration_link', + title: '链接管理', + path: '/pages/mall/admin/decoration/link', + componentKey: 'DecorationLink', + parentId: 'decoration', + groupId: 'decoration-manage', + order: 7 + }, + + // ========== 应用模块 ========== + { + id: 'app_statistic', + title: '应用统计', + path: '/pages/mall/admin/app/statistic', + componentKey: 'AppStatistic', + parentId: 'app', + groupId: 'app-manage', + order: 1 + }, + { + id: 'app_list', + title: '应用列表', + path: '/pages/mall/admin/app/list', + componentKey: 'AppList', + parentId: 'app', + groupId: 'app-manage', + order: 2 + }, + + // ========== 维护模块 ========== + // 开发配置 + { id: 'maintain_dev_config', title: '配置分类', path: '/pages/mall/admin/maintain/dev/config', componentKey: 'MaintainDevConfig', parentId: 'maintain', groupId: 'maintain-dev', order: 1 }, + { id: 'maintain_dev_data', title: '组合数据', path: '/pages/mall/admin/maintain/dev/data', componentKey: 'MaintainDevData', parentId: 'maintain', groupId: 'maintain-dev', order: 2 }, + { id: 'maintain_dev_task', title: '定时任务', path: '/pages/mall/admin/maintain/dev/task', componentKey: 'MaintainDevTask', parentId: 'maintain', groupId: 'maintain-dev', order: 3 }, + { id: 'maintain_dev_auth', title: '权限维护', path: '/pages/mall/admin/maintain/dev/auth', componentKey: 'MaintainDevAuth', parentId: 'maintain', groupId: 'maintain-dev', order: 4 }, + { id: 'maintain_dev_module', title: '模块配置', path: '/pages/mall/admin/maintain/dev/module', componentKey: 'MaintainDevModule', parentId: 'maintain', groupId: 'maintain-dev', order: 5 }, + { id: 'maintain_dev_event', title: '自定事件', path: '/pages/mall/admin/maintain/dev/event', componentKey: 'MaintainDevEvent', parentId: 'maintain', groupId: 'maintain-dev', order: 6 }, + + // 安全维护 + { id: 'maintain_security_cache', title: '刷新缓存', path: '/pages/mall/admin/maintain/security/cache', componentKey: 'MaintainSecurityCache', parentId: 'maintain', groupId: 'maintain-security', order: 1 }, + { id: 'maintain_security_log', title: '系统日志', path: '/pages/mall/admin/maintain/security/log', componentKey: 'MaintainSecurityLog', parentId: 'maintain', groupId: 'maintain-security', order: 2 }, + { id: 'maintain_security_upgrade', title: '在线升级', path: '/pages/mall/admin/maintain/security/upgrade', componentKey: 'MaintainSecurityUpgrade', parentId: 'maintain', groupId: 'maintain-security', order: 3 }, + + // 数据维护 + { id: 'maintain_data_logistics', title: '物流公司', path: '/pages/mall/admin/maintain/data/logistics', componentKey: 'MaintainDataLogistics', parentId: 'maintain', groupId: 'maintain-data', order: 1 }, + { id: 'maintain_data_city', title: '城市数据', path: '/pages/mall/admin/maintain/data/city', componentKey: 'MaintainDataCity', parentId: 'maintain', groupId: 'maintain-data', order: 2 }, + { id: 'maintain_data_clear', title: '清除数据', path: '/pages/mall/admin/maintain/data/clear', componentKey: 'MaintainDataClear', parentId: 'maintain', groupId: 'maintain-data', order: 3 }, + + // 对外接口 + { id: 'maintain_api_account', title: '账号管理', path: '/pages/mall/admin/maintain/api/account', componentKey: 'MaintainApiAccount', parentId: 'maintain', groupId: 'maintain-api', order: 1 }, + + // 语言设置 + { id: 'maintain_lang_list', title: '语言列表', path: '/pages/mall/admin/maintain/lang/list', componentKey: 'MaintainLangList', parentId: 'maintain', groupId: 'maintain-lang', order: 1 }, + { id: 'maintain_lang_detail', title: '语言详情', path: '/pages/mall/admin/maintain/lang/detail', componentKey: 'MaintainLangDetail', parentId: 'maintain', groupId: 'maintain-lang', order: 2 }, + { id: 'maintain_lang_region', title: '地区列表', path: '/pages/mall/admin/maintain/lang/region', componentKey: 'MaintainLangRegion', parentId: 'maintain', groupId: 'maintain-lang', order: 3 }, + { id: 'maintain_lang_config', title: '翻译配置', path: '/pages/mall/admin/maintain/lang/config', componentKey: 'MaintainLangConfig', parentId: 'maintain', groupId: 'maintain-lang', order: 4 }, + + // 开发工具 + { id: 'maintain_tool_db', title: '数据库管理', path: '/pages/mall/admin/maintain/tool/db', componentKey: 'MaintainToolDb', parentId: 'maintain', groupId: 'maintain-tool', order: 1 }, + { id: 'maintain_tool_file', title: '文件管理', path: '/pages/mall/admin/maintain/tool/file', componentKey: 'MaintainToolFile', parentId: 'maintain', groupId: 'maintain-tool', order: 2 }, + { id: 'maintain_tool_api', title: '接口管理', path: '/pages/mall/admin/maintain/tool/api', componentKey: 'MaintainToolApi', parentId: 'maintain', groupId: 'maintain-tool', order: 3 }, + { id: 'maintain_tool_dic', title: '数据字典', path: '/pages/mall/admin/maintain/tool/dic', componentKey: 'MaintainToolDic', parentId: 'maintain', groupId: 'maintain-tool', order: 4 }, + + // 系统信息 + { id: 'maintain_sys_info', title: '系统信息', path: '/pages/mall/admin/maintain/sys/info', componentKey: 'MaintainSysInfo', parentId: 'maintain', groupId: 'maintain-sys', order: 1 } ] /** diff --git a/pages/mall/admin/cms/article/list.uvue b/pages/mall/admin/cms/article/list.uvue index 51b3bdd9..60ac6697 100644 --- a/pages/mall/admin/cms/article/list.uvue +++ b/pages/mall/admin/cms/article/list.uvue @@ -1,15 +1,217 @@ + diff --git a/pages/mall/admin/marketing/member/config.uvue b/pages/mall/admin/marketing/member/config.uvue index a05be787..1247f77b 100644 --- a/pages/mall/admin/marketing/member/config.uvue +++ b/pages/mall/admin/marketing/member/config.uvue @@ -1,27 +1,225 @@ + diff --git a/pages/mall/admin/marketing/member/record.uvue b/pages/mall/admin/marketing/member/record.uvue index a3e6e598..2f6191ff 100644 --- a/pages/mall/admin/marketing/member/record.uvue +++ b/pages/mall/admin/marketing/member/record.uvue @@ -1,27 +1,187 @@ + diff --git a/pages/mall/admin/marketing/member/right.uvue b/pages/mall/admin/marketing/member/right.uvue new file mode 100644 index 00000000..c877fce4 --- /dev/null +++ b/pages/mall/admin/marketing/member/right.uvue @@ -0,0 +1,142 @@ + + + + + + + + diff --git a/pages/mall/admin/marketing/member/rights.uvue b/pages/mall/admin/marketing/member/rights.uvue deleted file mode 100644 index a9a7f04d..00000000 --- a/pages/mall/admin/marketing/member/rights.uvue +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - diff --git a/pages/mall/admin/marketing/member/type.uvue b/pages/mall/admin/marketing/member/type.uvue index 39096421..b4cd25ac 100644 --- a/pages/mall/admin/marketing/member/type.uvue +++ b/pages/mall/admin/marketing/member/type.uvue @@ -1,27 +1,147 @@ + diff --git a/pages/mall/admin/marketing/newcomer.uvue b/pages/mall/admin/marketing/newcomer.uvue deleted file mode 100644 index 0d63f4d0..00000000 --- a/pages/mall/admin/marketing/newcomer.uvue +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - diff --git a/pages/mall/admin/marketing/newcomer/index.uvue b/pages/mall/admin/marketing/newcomer/index.uvue new file mode 100644 index 00000000..ec3641ec --- /dev/null +++ b/pages/mall/admin/marketing/newcomer/index.uvue @@ -0,0 +1,521 @@ + + + + + + + diff --git a/pages/mall/admin/marketing/recharge/amount.uvue b/pages/mall/admin/marketing/recharge/amount.uvue deleted file mode 100644 index da03bc48..00000000 --- a/pages/mall/admin/marketing/recharge/amount.uvue +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - diff --git a/pages/mall/admin/marketing/recharge/config.uvue b/pages/mall/admin/marketing/recharge/config.uvue index 500d74e7..0ccbf32b 100644 --- a/pages/mall/admin/marketing/recharge/config.uvue +++ b/pages/mall/admin/marketing/recharge/config.uvue @@ -1,27 +1,187 @@ + diff --git a/pages/mall/admin/marketing/recharge/quota.uvue b/pages/mall/admin/marketing/recharge/quota.uvue new file mode 100644 index 00000000..fb29e37b --- /dev/null +++ b/pages/mall/admin/marketing/recharge/quota.uvue @@ -0,0 +1,383 @@ + + + + + + + + diff --git a/pages/mall/admin/marketing/seckill/config.uvue b/pages/mall/admin/marketing/seckill/config.uvue index 1b17b48e..bd7830f5 100644 --- a/pages/mall/admin/marketing/seckill/config.uvue +++ b/pages/mall/admin/marketing/seckill/config.uvue @@ -1,27 +1,528 @@ diff --git a/pages/mall/admin/marketing/seckill/goods.uvue b/pages/mall/admin/marketing/seckill/goods.uvue deleted file mode 100644 index f3d6470a..00000000 --- a/pages/mall/admin/marketing/seckill/goods.uvue +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - diff --git a/pages/mall/admin/marketing/seckill/list.uvue b/pages/mall/admin/marketing/seckill/list.uvue index 51cbd7d7..b84a1bda 100644 --- a/pages/mall/admin/marketing/seckill/list.uvue +++ b/pages/mall/admin/marketing/seckill/list.uvue @@ -1,15 +1,119 @@