From 77f3686e0f0b522a10b6dbcf6a87c53c91d0c59f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Tue, 16 Sep 2025 23:40:23 +0800 Subject: [PATCH] =?UTF-8?q?refactor(sdy):=20=E9=87=8D=E6=9E=84=E7=BB=8F?= =?UTF-8?q?=E9=94=80=E5=95=86=E7=94=B3=E8=AF=B7=E7=9B=B8=E5=85=B3=E7=BB=84?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修改了 shopDealerApply 组件的搜索和导入功能 - 新增了 shopDealerApplyEdit 组件用于编辑申请信息 - 删除了未使用的 Import组件 - 调整了表单验证规则和数据处理逻辑 --- .../bsyxGrade/components/bszxGradeEdit.vue | 1 + src/views/passport/qrConfirm/index.vue | 2 +- src/views/sdy/shopDealerApply/index.vue | 2 +- .../components/shop-dealer-apply-import.vue | 2 +- src/views/sdy/shopDealerUser/README.md | 100 ----- .../sdy/shopDealerUser/components/Import.vue | 110 ----- .../sdy/shopDealerUser/components/search.vue | 387 +++++++++-------- .../components/shopDealerApplyEdit.vue | 407 ++++++++++++++++++ .../components/shopDealerUserEdit.vue | 363 ---------------- src/views/sdy/shopDealerUser/index.vue | 351 ++++++++++----- 10 files changed, 862 insertions(+), 863 deletions(-) delete mode 100644 src/views/sdy/shopDealerUser/README.md delete mode 100644 src/views/sdy/shopDealerUser/components/Import.vue create mode 100644 src/views/sdy/shopDealerUser/components/shopDealerApplyEdit.vue delete mode 100644 src/views/sdy/shopDealerUser/components/shopDealerUserEdit.vue diff --git a/src/views/bsyx/bsyxGrade/components/bszxGradeEdit.vue b/src/views/bsyx/bsyxGrade/components/bszxGradeEdit.vue index 1908dd0..e76adc5 100644 --- a/src/views/bsyx/bsyxGrade/components/bszxGradeEdit.vue +++ b/src/views/bsyx/bsyxGrade/components/bszxGradeEdit.vue @@ -24,6 +24,7 @@ allow-clear placeholder="请输入年级" v-model:value="form.name" + @pressEnter="save" /> diff --git a/src/views/passport/qrConfirm/index.vue b/src/views/passport/qrConfirm/index.vue index 9ce819f..75449b7 100644 --- a/src/views/passport/qrConfirm/index.vue +++ b/src/views/passport/qrConfirm/index.vue @@ -79,7 +79,7 @@ import { useRoute, useRouter } from 'vue-router'; import { message } from 'ant-design-vue'; import { UserOutlined, ExclamationCircleOutlined } from '@ant-design/icons-vue'; import { confirmQrLogin, scanQrCode, type QrLoginConfirmRequest } from '@/api/passport/qrLogin'; -import { getUserInfo } from '@/api/system/user'; +import { getUserInfo } from '@/api/layout'; import { getToken } from '@/utils/token-util'; const route = useRoute(); diff --git a/src/views/sdy/shopDealerApply/index.vue b/src/views/sdy/shopDealerApply/index.vue index aa9d039..34767b8 100644 --- a/src/views/sdy/shopDealerApply/index.vue +++ b/src/views/sdy/shopDealerApply/index.vue @@ -115,7 +115,7 @@ const datasource: DatasourceFunction = ({ if (filters) { where.status = filters.status; } - where.type = 0; + where.type = 4; return pageShopDealerApply({ ...where, ...orders, diff --git a/src/views/sdy/shopDealerApplyRs/components/shop-dealer-apply-import.vue b/src/views/sdy/shopDealerApplyRs/components/shop-dealer-apply-import.vue index 2ce758f..32c2917 100644 --- a/src/views/sdy/shopDealerApplyRs/components/shop-dealer-apply-import.vue +++ b/src/views/sdy/shopDealerApplyRs/components/shop-dealer-apply-import.vue @@ -23,7 +23,7 @@
只能上传xls、xlsx文件, 下载导入模板 diff --git a/src/views/sdy/shopDealerUser/README.md b/src/views/sdy/shopDealerUser/README.md deleted file mode 100644 index 0f48844..0000000 --- a/src/views/sdy/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) -- ✅ 实现基础的导入导出功能 -- ✅ 添加数据验证和错误处理 -- ✅ 优化用户体验和界面交互 -- ✅ 完善文档说明 diff --git a/src/views/sdy/shopDealerUser/components/Import.vue b/src/views/sdy/shopDealerUser/components/Import.vue deleted file mode 100644 index fbf5244..0000000 --- a/src/views/sdy/shopDealerUser/components/Import.vue +++ /dev/null @@ -1,110 +0,0 @@ - - - - - - diff --git a/src/views/sdy/shopDealerUser/components/search.vue b/src/views/sdy/shopDealerUser/components/search.vue index 19e7393..3a97655 100644 --- a/src/views/sdy/shopDealerUser/components/search.vue +++ b/src/views/sdy/shopDealerUser/components/search.vue @@ -1,206 +1,219 @@ + + diff --git a/src/views/sdy/shopDealerUser/components/shopDealerApplyEdit.vue b/src/views/sdy/shopDealerUser/components/shopDealerApplyEdit.vue new file mode 100644 index 0000000..bad4d1f --- /dev/null +++ b/src/views/sdy/shopDealerUser/components/shopDealerApplyEdit.vue @@ -0,0 +1,407 @@ + + + + + + diff --git a/src/views/sdy/shopDealerUser/components/shopDealerUserEdit.vue b/src/views/sdy/shopDealerUser/components/shopDealerUserEdit.vue deleted file mode 100644 index 071bb54..0000000 --- a/src/views/sdy/shopDealerUser/components/shopDealerUserEdit.vue +++ /dev/null @@ -1,363 +0,0 @@ - - - - - - diff --git a/src/views/sdy/shopDealerUser/index.vue b/src/views/sdy/shopDealerUser/index.vue index 5104023..2b1454a 100644 --- a/src/views/sdy/shopDealerUser/index.vue +++ b/src/views/sdy/shopDealerUser/index.vue @@ -3,7 +3,7 @@ @@ -59,32 +70,37 @@ import {createVNode, ref} from 'vue'; import {message, Modal} from 'ant-design-vue'; import { ExclamationCircleOutlined, + CheckOutlined, + CloseOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons-vue'; import type {EleProTable} from 'ele-admin-pro'; -import {toDateString} from 'ele-admin-pro'; import type { DatasourceFunction, ColumnItem } from 'ele-admin-pro/es/ele-pro-table/types'; import Search from './components/search.vue'; import {getPageTitle} from '@/utils/common'; -import ShopDealerUserEdit from './components/shopDealerUserEdit.vue'; -import {pageShopDealerUser, removeShopDealerUser, removeBatchShopDealerUser} from '@/api/shop/shopDealerUser'; -import type {ShopDealerUser, ShopDealerUserParam} from '@/api/shop/shopDealerUser/model'; +import ShopDealerApplyEdit from './components/shopDealerApplyEdit.vue'; +import { + pageShopDealerApply, + removeShopDealerApply, + removeBatchShopDealerApply, + batchApproveShopDealerApply, + updateShopDealerApply +} from '@/api/shop/shopDealerApply'; +import type {ShopDealerApply, ShopDealerApplyParam} from '@/api/shop/shopDealerApply/model'; // 表格实例 const tableRef = ref | null>(null); // 表格选中数据 -const selection = ref([]); +const selection = ref([]); // 当前编辑数据 -const current = ref(null); +const current = ref(null); // 是否显示编辑弹窗 const showEdit = ref(false); -// 是否显示批量移动弹窗 -const showMove = ref(false); // 加载状态 const loading = ref(true); @@ -99,8 +115,9 @@ const datasource: DatasourceFunction = ({ if (filters) { where.status = filters.status; } - where.type = 0; - return pageShopDealerUser({ + where.type = 4; + where.applyStatus = 20; + return pageShopDealerApply({ ...where, ...orders, page, @@ -111,114 +128,185 @@ const datasource: DatasourceFunction = ({ // 表格列配置 const columns = ref([ { - title: '用户ID', - dataIndex: 'userId', - key: 'userId', + title: 'ID', + dataIndex: 'applyId', + key: 'applyId', align: 'center', width: 80, fixed: 'left' }, { - title: '用电户号', - dataIndex: 'qrcode', - key: 'qrcode', + title: '申请人信息', + key: 'applicantInfo', + align: 'left', + fixed: 'left', + customRender: ({record}) => { + return `${record.realName || '-'} (${record.mobile || '-'})`; + } + }, + { + title: '申请方式', + dataIndex: 'applyType', + key: 'applyType', + align: 'center', + width: 120, + customRender: ({text}) => { + const typeMap = { + 10: {text: '需审核', color: 'orange'}, + 20: {text: '免审核', color: 'green'} + }; + const type = typeMap[text] || {text: '未知', color: 'default'}; + return {type: 'tag', props: {color: type.color}, children: type.text}; + } + }, + { + title: '审核状态', + dataIndex: 'applyStatus', + key: 'applyStatus', align: 'center', width: 120 }, { - title: '单位名称', - key: 'userInfo', - align: 'left', - width: 200, - fixed: 'left', - customRender: ({record}) => { - return `${record.realName || ''} (${record.mobile || ''})`; - } - }, - { - title: '电量', - key: 'money', - align: 'center', - width: 180 - }, - { - title: '供电局', - key: 'money4', - align: 'center' - }, - { - title: '供电分局', - key: 'money3', - align: 'center' - }, - { - title: '供电所', - key: 'money2', - align: 'center' - }, - { - title: '渠道负责人', - key: 'comments', - align: 'center' - }, - { - title: '状态', - key: 'userStatus', + title: '推荐人', + dataIndex: 'refereeId', + key: 'refereeId', align: 'center', width: 100, - customRender: ({record}) => { - if (record.isDelete === 1) { - return {type: 'tag', props: {color: 'red'}, children: '已删除'}; - } - return {type: 'tag', props: {color: 'green'}, children: '正常'}; - } + customRender: ({text}) => text ? `ID: ${text}` : '无' + }, + // { + // title: '申请时间', + // dataIndex: 'applyTime', + // key: 'applyTime', + // align: 'center', + // width: 120, + // customRender: ({ text }) => text ? toDateString(new Date(text), 'yyyy-MM-dd HH:mm') : '-' + // }, + // { + // title: '审核时间', + // dataIndex: 'auditTime', + // key: 'auditTime', + // align: 'center', + // customRender: ({ text }) => text ? toDateString(new Date(text), 'yyyy-MM-dd HH:mm') : '-' + // }, + { + title: '驳回原因', + dataIndex: 'rejectReason', + key: 'rejectReason', + align: 'left', + ellipsis: true, + customRender: ({text}) => text || '-' }, { title: '创建时间', dataIndex: 'createTime', key: 'createTime', align: 'center', - width: 120, sorter: true, - ellipsis: true, - customRender: ({text}) => text ? toDateString(text, 'yyyy-MM-dd') : '-' + ellipsis: true }, { title: '操作', key: 'action', - width: 220, fixed: 'right', align: 'center', + width: 380, hideInSetting: true } ]); /* 搜索 */ -const reload = (where?: ShopDealerUserParam) => { +const reload = (where?: ShopDealerApplyParam) => { selection.value = []; tableRef?.value?.reload({where: where}); }; +/* 审核通过 */ +const approveApply = (row: ShopDealerApply) => { + Modal.confirm({ + title: '审核通过确认', + content: `确定要通过 ${row.realName} 的经销商申请吗?`, + icon: createVNode(CheckOutlined), + okText: '确认通过', + okType: 'primary', + cancelText: '取消', + onOk: async () => { + const hide = message.loading('正在处理审核...', 0); + try { + await updateShopDealerApply({ + ...row, + applyId: row.applyId, + applyStatus: 20 + }); + hide(); + message.success('审核通过成功'); + reload(); + } catch (error: any) { + hide(); + message.error(error.message || '审核失败,请重试'); + } + } + }); +}; + +/* 审核驳回 */ +const rejectApply = (row: ShopDealerApply) => { + let rejectReason = ''; + Modal.confirm({ + title: '审核驳回', + content: createVNode('div', null, [ + createVNode('p', null, `申请人: ${row.realName} (${row.mobile})`), + createVNode('p', {style: 'margin-top: 12px;'}, '请输入驳回原因:'), + createVNode('textarea', { + placeholder: '请输入驳回原因...', + style: 'width: 100%; height: 80px; margin-top: 8px; padding: 8px; border: 1px solid #d9d9d9; border-radius: 4px;', + onInput: (e: any) => { + rejectReason = e.target.value; + } + }) + ]), + icon: createVNode(CloseOutlined), + okText: '确认驳回', + okType: 'danger', + cancelText: '取消', + onOk: async () => { + if (!rejectReason.trim()) { + message.error('请输入驳回原因'); + return Promise.reject(); + } + const hide = message.loading('正在处理审核...', 0); + try { + await updateShopDealerApply({ + ...row, + applyStatus: 30, + rejectReason: rejectReason.trim() + }); + hide(); + message.success('审核驳回成功'); + reload(); + } catch (error: any) { + hide(); + message.error(error.message || '审核失败,请重试'); + } + } + }); +}; + /* 打开编辑弹窗 */ -const openEdit = (row?: ShopDealerUser) => { +const openEdit = (row?: ShopDealerApply) => { current.value = row ?? null; showEdit.value = true; }; -/* 打开批量移动弹窗 */ -const openMove = () => { - showMove.value = true; -}; - /* 删除单个 */ -const remove = (row: ShopDealerUser) => { - if (!row.id) { +const remove = (row: ShopDealerApply) => { + if (!row.applyId) { message.error('删除失败:缺少必要参数'); return; } - const hide = message.loading('正在删除分销商用户...', 0); - removeShopDealerUser(row.id) + const hide = message.loading('正在删除申请记录...', 0); + removeShopDealerApply(row.applyId) .then((msg) => { hide(); message.success(msg || '删除成功'); @@ -237,7 +325,7 @@ const removeBatch = () => { return; } - const validIds = selection.value.filter(d => d.id).map(d => d.id); + const validIds = selection.value.filter(d => d.applyId).map(d => d.applyId); if (!validIds.length) { message.error('选中的数据中没有有效的ID'); return; @@ -245,7 +333,7 @@ const removeBatch = () => { Modal.confirm({ title: '批量删除确认', - content: `确定要删除选中的 ${validIds.length} 条分销商用户记录吗?此操作不可恢复。`, + content: `确定要删除选中的 ${validIds.length} 条申请记录吗?此操作不可恢复。`, icon: createVNode(ExclamationCircleOutlined), maskClosable: true, okText: '确认删除', @@ -253,7 +341,7 @@ const removeBatch = () => { cancelText: '取消', onOk: () => { const hide = message.loading(`正在删除 ${validIds.length} 条记录...`, 0); - removeBatchShopDealerUser(validIds) + removeBatchShopDealerApply(validIds) .then((msg) => { hide(); message.success(msg || `成功删除 ${validIds.length} 条记录`); @@ -268,13 +356,60 @@ const removeBatch = () => { }); }; +/* 批量通过 */ +const batchApprove = () => { + if (!selection.value.length) { + message.error('请至少选择一条数据'); + return; + } + + const pendingApplies = selection.value.filter(item => item.applyStatus === 10); + if (!pendingApplies.length) { + message.error('所选申请中没有待审核的记录'); + return; + } + + Modal.confirm({ + title: '批量通过确认', + content: `确定要通过选中的 ${pendingApplies.length} 个申请吗?`, + icon: createVNode(ExclamationCircleOutlined), + okText: '确认通过', + okType: 'primary', + cancelText: '取消', + onOk: async () => { + const hide = message.loading('正在批量通过...', 0); + try { + const ids = pendingApplies.map(item => item.applyId); + await batchApproveShopDealerApply(ids); + hide(); + message.success(`成功通过 ${pendingApplies.length} 个申请`); + selection.value = []; + reload(); + } catch (error: any) { + hide(); + message.error(error.message || '批量审核失败,请重试'); + } + } + }); +}; + +/* 导出数据 */ +const exportData = () => { + const hide = message.loading('正在导出申请数据...', 0); + // 这里调用导出API + setTimeout(() => { + hide(); + message.success('申请数据导出成功'); + }, 2000); +}; + /* 查询 */ const query = () => { loading.value = true; }; /* 自定义行属性 */ -const customRow = (record: ShopDealerUser) => { +const customRow = (record: ShopDealerApply) => { return { // 行点击事件 onClick: () => { @@ -291,7 +426,7 @@ query(); @@ -335,6 +470,22 @@ export default { } } +.ele-text-success { + color: #52c41a; + + &:hover { + color: #73d13d; + } +} + +.ele-text-warning { + color: #faad14; + + &:hover { + color: #ffc53d; + } +} + .ele-text-danger { color: #ff4d4f;