diff --git a/.env.development b/.env.development index b8ccd8b..fbcc74b 100644 --- a/.env.development +++ b/.env.development @@ -1,5 +1,5 @@ VITE_APP_NAME=后台管理(开发环境) -#VITE_API_URL=http://127.0.0.1:9200/api +VITE_API_URL=http://127.0.0.1:9200/api #VITE_SERVER_API_URL=http://127.0.0.1:8000/api diff --git a/src/api/layout/index.ts b/src/api/layout/index.ts index 7910080..4893c09 100644 --- a/src/api/layout/index.ts +++ b/src/api/layout/index.ts @@ -6,7 +6,6 @@ import {SERVER_API_URL} from '@/config/setting'; import { Company } from '@/api/system/company/model'; import { CmsWebsite } from '@/api/cms/cmsWebsite/model'; import {Menu} from "@/api/system/menu/model"; -import {getLang} from "@/utils/common"; /** * 获取当前登录的用户信息、菜单、权限、角色 @@ -28,9 +27,7 @@ export async function getSiteInfo() { const res = await request.get>( '/shop/getShopInfo', { - params: { - lang: getLang() - } + params: {} } ); if (res.data.code === 0 && res.data.data) { diff --git a/src/api/sdy/sdyDealerOrder/index.ts b/src/api/sdy/sdyDealerOrder/index.ts new file mode 100644 index 0000000..28583ae --- /dev/null +++ b/src/api/sdy/sdyDealerOrder/index.ts @@ -0,0 +1,120 @@ +import request from '@/utils/request'; +import type {ApiResult} from '@/api'; +import type {ShopDealerOrder, ShopDealerOrderParam} from './model'; +import {utils, writeFile} from 'xlsx'; +import {message} from 'ant-design-vue'; +import {getTenantId} from '@/utils/domain'; +import {listShopDealerOrder} from "@/api/shop/shopDealerOrder"; + +/** + * 导入分销商订单 + */ +export async function importSdyDealerOrder(file: File) { + const formData = new FormData(); + formData.append('file', file); + const res = await request.post>( + '/sdy/sdy-dealer-order/import', + formData + ); + if (res.data.code === 0) { + return res.data.message; + } + return Promise.reject(new Error(res.data.message)); +} + +/** + * 导出分销商订单 + */ +export async function exportSdyDealerOrder(params?: ShopDealerOrderParam) { + // 显示导出加载提示 + message.loading('正在准备导出数据...', 0); + + try { + // 获取数据 + const list = await listShopDealerOrder(params); + + if (!list || list.length === 0) { + message.destroy(); + message.warning('没有数据可以导出'); + return; + } + + // 构建导出数据 + const array: (string | number)[][] = [ + [ + '订单ID', + '买家用户ID', + '订单总金额', + '一级分销商ID', + '一级佣金', + '二级分销商ID', + '二级佣金', + '三级分销商ID', + '三级佣金', + '订单状态', + '结算状态', + '结算时间', + '创建时间' + ] + ]; + + list.forEach((order: ShopDealerOrder) => { + array.push([ + order.orderId || '', + order.userId || '', + order.orderPrice || '0', + order.firstUserId || '', + order.firstMoney || '0', + order.secondUserId || '', + order.secondMoney || '0', + order.thirdUserId || '', + order.thirdMoney || '0', + order.isInvalid === 0 ? '有效' : '失效', + order.isSettled === 0 ? '未结算' : '已结算', + order.settleTime ? new Date(order.settleTime).toLocaleString() : '', + order.createTime || '' + ]); + }); + + // 创建工作簿 + const sheetName = `shop_dealer_order_${getTenantId()}`; + const workbook = { + SheetNames: [sheetName], + Sheets: {} + }; + + const sheet = utils.aoa_to_sheet(array); + workbook.Sheets[sheetName] = sheet; + + // 设置列宽 + sheet['!cols'] = [ + {wch: 15}, // 订单ID + {wch: 12}, // 买家用户ID + {wch: 12}, // 订单总金额 + {wch: 15}, // 一级分销商ID + {wch: 12}, // 一级佣金 + {wch: 15}, // 二级分销商ID + {wch: 12}, // 二级佣金 + {wch: 15}, // 三级分销商ID + {wch: 12}, // 三级佣金 + {wch: 10}, // 订单状态 + {wch: 10}, // 结算状态 + {wch: 20}, // 结算时间 + {wch: 20} // 创建时间 + ]; + + message.destroy(); + message.loading('正在生成Excel文件...', 0); + + // 延迟写入文件,确保消息提示显示 + setTimeout(() => { + writeFile(workbook, `${sheetName}.xlsx`); + message.destroy(); + message.success(`成功导出 ${list.length} 条记录`); + }, 1000); + + } catch (error: any) { + message.destroy(); + message.error(error.message || '导出失败,请重试'); + } +} diff --git a/src/api/sdy/sdyDealerOrder/model/index.ts b/src/api/sdy/sdyDealerOrder/model/index.ts new file mode 100644 index 0000000..d98a4b6 --- /dev/null +++ b/src/api/sdy/sdyDealerOrder/model/index.ts @@ -0,0 +1,53 @@ +import type { PageParam } from '@/api'; + +/** + * 分销商订单记录表 + */ +export interface ShopDealerOrder { + // 主键ID + id?: number; + // 买家用户ID + userId?: number; + // 订单ID + orderId?: number; + // 订单总金额(不含运费) + orderPrice?: string; + // 分销商用户id(一级) + firstUserId?: number; + // 分销商用户id(二级) + secondUserId?: number; + // 分销商用户id(三级) + thirdUserId?: number; + // 分销佣金(一级) + firstMoney?: string; + // 分销佣金(二级) + secondMoney?: string; + // 分销佣金(三级) + thirdMoney?: string; + // 订单是否失效(0未失效 1已失效) + isInvalid?: number; + // 佣金结算(0未结算 1已结算) + isSettled?: number; + // 结算时间 + settleTime?: number; + // 商城ID + tenantId?: number; + // 创建时间 + createTime?: string; + // 修改时间 + updateTime?: string; +} + +/** + * 分销商订单记录表搜索条件 + */ +export interface ShopDealerOrderParam extends PageParam { + id?: number; + orderId?: number; + orderNo?: string; + productName?: string; + userId?: number; + isInvalid?: number; + isSettled?: number; + keywords?: string; +} diff --git a/src/api/shop/shopDealerOrder/index.ts b/src/api/shop/shopDealerOrder/index.ts index abb1d1d..dab3b28 100644 --- a/src/api/shop/shopDealerOrder/index.ts +++ b/src/api/shop/shopDealerOrder/index.ts @@ -1,6 +1,9 @@ import request from '@/utils/request'; import type { ApiResult, PageResult } from '@/api'; import type { ShopDealerOrder, ShopDealerOrderParam } from './model'; +import { utils, writeFile } from 'xlsx'; +import { message } from 'ant-design-vue'; +import { getTenantId } from '@/utils/domain'; /** * 分页查询分销商订单记录表 @@ -103,3 +106,116 @@ export async function getShopDealerOrder(id: number) { } return Promise.reject(new Error(res.data.message)); } + +/** + * 导入分销商订单 + */ +export async function importShopDealerOrder(file: File) { + const formData = new FormData(); + formData.append('file', file); + const res = await request.post>( + '/shop/shop-dealer-order/import', + formData + ); + if (res.data.code === 0) { + return res.data.message; + } + return Promise.reject(new Error(res.data.message)); +} + +/** + * 导出分销商订单 + */ +export async function exportShopDealerOrder(params?: ShopDealerOrderParam) { + // 显示导出加载提示 + message.loading('正在准备导出数据...', 0); + + try { + // 获取数据 + const list = await listShopDealerOrder(params); + + if (!list || list.length === 0) { + message.destroy(); + message.warning('没有数据可以导出'); + return; + } + + // 构建导出数据 + const array: (string | number)[][] = [ + [ + '订单ID', + '买家用户ID', + '订单总金额', + '一级分销商ID', + '一级佣金', + '二级分销商ID', + '二级佣金', + '三级分销商ID', + '三级佣金', + '订单状态', + '结算状态', + '结算时间', + '创建时间' + ] + ]; + + list.forEach((order: ShopDealerOrder) => { + array.push([ + order.orderId || '', + order.userId || '', + order.orderPrice || '0', + order.firstUserId || '', + order.firstMoney || '0', + order.secondUserId || '', + order.secondMoney || '0', + order.thirdUserId || '', + order.thirdMoney || '0', + order.isInvalid === 0 ? '有效' : '失效', + order.isSettled === 0 ? '未结算' : '已结算', + order.settleTime ? new Date(order.settleTime).toLocaleString() : '', + order.createTime || '' + ]); + }); + + // 创建工作簿 + const sheetName = `shop_dealer_order_${getTenantId()}`; + const workbook = { + SheetNames: [sheetName], + Sheets: {} + }; + + const sheet = utils.aoa_to_sheet(array); + workbook.Sheets[sheetName] = sheet; + + // 设置列宽 + sheet['!cols'] = [ + { wch: 15 }, // 订单ID + { wch: 12 }, // 买家用户ID + { wch: 12 }, // 订单总金额 + { wch: 15 }, // 一级分销商ID + { wch: 12 }, // 一级佣金 + { wch: 15 }, // 二级分销商ID + { wch: 12 }, // 二级佣金 + { wch: 15 }, // 三级分销商ID + { wch: 12 }, // 三级佣金 + { wch: 10 }, // 订单状态 + { wch: 10 }, // 结算状态 + { wch: 20 }, // 结算时间 + { wch: 20 } // 创建时间 + ]; + + message.destroy(); + message.loading('正在生成Excel文件...', 0); + + // 延迟写入文件,确保消息提示显示 + setTimeout(() => { + writeFile(workbook, `${sheetName}.xlsx`); + message.destroy(); + message.success(`成功导出 ${list.length} 条记录`); + }, 1000); + + } catch (error: any) { + message.destroy(); + message.error(error.message || '导出失败,请重试'); + } +} diff --git a/src/api/shop/shopDealerOrder/model/index.ts b/src/api/shop/shopDealerOrder/model/index.ts index d98a4b6..167bb84 100644 --- a/src/api/shop/shopDealerOrder/model/index.ts +++ b/src/api/shop/shopDealerOrder/model/index.ts @@ -8,6 +8,8 @@ export interface ShopDealerOrder { id?: number; // 买家用户ID userId?: number; + // 买家用户昵称 + nickname?: string; // 订单ID orderId?: number; // 订单总金额(不含运费) @@ -24,12 +26,24 @@ export interface ShopDealerOrder { secondMoney?: string; // 分销佣金(三级) thirdMoney?: string; + // 一级分销商昵称 + firstNickname?: string; + // 二级分销商昵称 + secondNickname?: string; + // 三级分销商昵称 + thirdNickname?: string; + // 分销比例 + rate?: number; + // 商品单价 + price?: string; // 订单是否失效(0未失效 1已失效) isInvalid?: number; // 佣金结算(0未结算 1已结算) isSettled?: number; // 结算时间 settleTime?: number; + // 订单备注 + comments?: string; // 商城ID tenantId?: number; // 创建时间 diff --git a/src/api/shop/shopDealerUser/model/index.ts b/src/api/shop/shopDealerUser/model/index.ts index 1b3bc22..d443ef2 100644 --- a/src/api/shop/shopDealerUser/model/index.ts +++ b/src/api/shop/shopDealerUser/model/index.ts @@ -20,6 +20,10 @@ export interface ShopDealerUser { freezeMoney?: string; // 累积提现佣金 totalMoney?: string; + // 佣金比例 + rate?: string; + // 单价 + price?: string; // 推荐人用户ID refereeId?: number; // 成员数量(一级) diff --git a/src/layout/components/header-tools.vue b/src/layout/components/header-tools.vue index 2deb124..fcfc410 100644 --- a/src/layout/components/header-tools.vue +++ b/src/layout/components/header-tools.vue @@ -141,7 +141,7 @@ import { FullscreenExitOutlined } from '@ant-design/icons-vue'; import {storeToRefs} from 'pinia'; -import {copyText, openUrl} from '@/utils/common'; +import {copyText, openNew, openUrl} from '@/utils/common'; import {useThemeStore} from '@/store/modules/theme'; import HeaderNotice from './header-notice.vue'; import PasswordModal from './password-modal.vue'; diff --git a/src/views/cms/cmsLink/components/cmsLinkEdit.vue b/src/views/cms/cmsLink/components/cmsLinkEdit.vue index fb3ef24..f8418a8 100644 --- a/src/views/cms/cmsLink/components/cmsLinkEdit.vue +++ b/src/views/cms/cmsLink/components/cmsLinkEdit.vue @@ -131,7 +131,6 @@ const { form, resetFields, assignFields } = useFormData({ name: '', url: '', sortNumber: 100, - lang: getLang(), categoryId: undefined, comments: undefined }); diff --git a/src/views/sdy/shopDealerApply/index.vue b/src/views/sdy/shopDealerApply/index.vue index 0935dfc..a8a0a99 100644 --- a/src/views/sdy/shopDealerApply/index.vue +++ b/src/views/sdy/shopDealerApply/index.vue @@ -139,11 +139,11 @@ const datasource: DatasourceFunction = ({ // 表格列配置 const columns = ref([ { - title: 'ID', - dataIndex: 'applyId', - key: 'applyId', + title: '用户ID', + dataIndex: 'userId', + key: 'userId', align: 'center', - width: 80, + width: 90, fixed: 'left' }, { @@ -425,7 +425,7 @@ const customRow = (record: ShopDealerApply) => { }, // 行双击事件 onDblclick: () => { - // openEdit(record); + openEdit(record); } }; }; @@ -438,67 +438,3 @@ export default { }; - diff --git a/src/views/sdy/shopDealerOrder/components/Import.vue b/src/views/sdy/shopDealerOrder/components/Import.vue new file mode 100644 index 0000000..cc7cdef --- /dev/null +++ b/src/views/sdy/shopDealerOrder/components/Import.vue @@ -0,0 +1,79 @@ + + + + diff --git a/src/views/sdy/shopDealerOrder/components/search.vue b/src/views/sdy/shopDealerOrder/components/search.vue index 4d84d64..dded660 100644 --- a/src/views/sdy/shopDealerOrder/components/search.vue +++ b/src/views/sdy/shopDealerOrder/components/search.vue @@ -1,6 +1,5 @@ - + \ No newline at end of file diff --git a/src/views/shop/shopDealerUser/README.md b/src/views/shop/shopDealerUser/README.md deleted file mode 100644 index 0f48844..0000000 --- a/src/views/shop/shopDealerUser/README.md +++ /dev/null @@ -1,100 +0,0 @@ -# 分销商用户管理模块 - -## 功能说明 - -本模块提供了完整的分销商用户管理功能,包括: - -### 基础功能 -- ✅ 用户列表查看 -- ✅ 用户信息编辑 -- ✅ 用户详情查看 -- ✅ 用户删除(单个/批量) -- ✅ 关键词搜索 - -### 导入导出功能 -- ✅ Excel 数据导出 -- ✅ Excel 数据导入 -- ✅ 导入数据验证 -- ✅ 错误处理 - -## 导入导出使用说明 - -### 导出功能 -1. 点击"导出xls"按钮 -2. 系统会根据当前搜索条件导出数据 -3. 导出的Excel文件包含以下字段: - - 用户ID - - 姓名 - - 手机号 - - 可提现佣金 - - 冻结佣金 - - 累计提现 - - 推荐人ID - - 一级成员数 - - 二级成员数 - - 三级成员数 - - 专属二维码 - - 状态 - - 创建时间 - - 更新时间 - -### 导入功能 -1. 点击"导入xls"按钮 -2. 拖拽或选择Excel文件(支持.xls和.xlsx格式) -3. 文件大小限制:10MB以内 -4. 导入格式要求: - - 必填字段:用户ID、姓名、手机号 - - 佣金字段请填写数字,不要包含货币符号 - - 状态字段:正常 或 已删除 - - 推荐人ID必须是已存在的用户ID - -### 数据格式示例 - -| 用户ID | 姓名 | 手机号 | 可提现佣金 | 冻结佣金 | 累计提现 | 推荐人ID | 一级成员数 | 二级成员数 | 三级成员数 | 专属二维码 | 状态 | -|--------|------|--------|------------|----------|----------|----------|------------|------------|------------|------------|------| -| 1001 | 张三 | 13800138000 | 100.50 | 50.00 | 200.00 | 1000 | 5 | 3 | 2 | DEALER_1001_xxx | 正常 | -| 1002 | 李四 | 13900139000 | 200.00 | 0.00 | 150.00 | | 2 | 1 | 0 | | 正常 | - -## 技术实现 - -### 文件结构 -``` -src/views/shop/shopDealerUser/ -├── index.vue # 主页面 -├── components/ -│ ├── search.vue # 搜索组件(包含导入导出功能) -│ ├── Import.vue # 导入弹窗组件 -│ └── shopDealerUserEdit.vue # 编辑弹窗组件 -└── README.md # 说明文档 -``` - -### API 接口 -```typescript -// 导入接口 -POST /shop/shop-dealer-user/import -Content-Type: multipart/form-data - -// 导出接口 -GET /shop/shop-dealer-user/export -Response-Type: blob -``` - -### 依赖库 -- `xlsx`: Excel文件处理 -- `dayjs`: 日期格式化 -- `ant-design-vue`: UI组件库 - -## 注意事项 - -1. **数据安全**:导入功能会直接操作数据库,请确保导入的数据准确无误 -2. **性能考虑**:大量数据导入时可能需要较长时间,请耐心等待 -3. **错误处理**:导入失败时会显示具体错误信息,请根据提示修正数据 -4. **权限控制**:确保用户有相应的导入导出权限 - -## 更新日志 - -### v1.0.0 (2024-12-19) -- ✅ 实现基础的导入导出功能 -- ✅ 添加数据验证和错误处理 -- ✅ 优化用户体验和界面交互 -- ✅ 完善文档说明