Files
mp-10584/src/views/shop/shopDealerUserDelivery/index.vue
赵忠林 055e53e06e feat(shop): 添加小区、配送员、门店等相关功能模块
- 新增 ShopCommunity 相关 API 接口和模型定义
- 新增 ShopRider 配送员管理模块及相应接口实现
- 新增 ShopStore 门店管理模块及数据模型
- 新增 ShopStoreRider 门店配送员关联关系管理
- 新增 ShopStoreUser 店员管理功能模块
- 在配送员用户界面添加所属门店字段显示
- 重构配送员相关组件和页面实现
- 添加小区选择组件及相应的交互功能
- 实现完整的 CRUD 操作接口包括分页、新增、修改、删除等
- 添加批量操作功能支持
- 优化数据表格展示和搜索功能
2026-01-30 15:04:18 +08:00

360 lines
9.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<a-page-header :title="getPageTitle()" @back="() => $router.go(-1)">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="id"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'shopName'">
<div class="text-purple-500">{{ record.shopName || '-' }}</div>
</template>
<template v-if="column.key === 'type'">
<a-tag v-if="record.type === 0">分销商</a-tag>
<a-tag v-if="record.type === 1" color="orange">门店</a-tag>
<a-tag v-if="record.type === 2" color="purple">配送员</a-tag>
</template>
<template v-if="column.key === 'qrcode'">
<QrcodeOutlined :style="{fontSize: '24px'}" @click="openQrCode(record)" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<ShopDealerUserEdit v-model:visible="showEdit" :data="current" @done="reload" />
<!-- 二维码预览 -->
<a-modal
v-model:visible="showQrModal"
:title="qrModalTitle"
:footer="null"
:width="380"
centered
destroy-on-close
>
<div style="display: flex; justify-content: center">
<a-image v-if="qrModalUrl" :src="qrModalUrl" :width="280" :preview="false" />
</div>
<div style="display: flex; justify-content: center; margin-top: 12px">
<a-space>
<a-button @click="copyQrUrl">复制链接</a-button>
<a-button type="primary" @click="openQrInNewTab">打开原图</a-button>
</a-space>
</div>
</a-modal>
</a-page-header>
</template>
<script lang="ts" setup>
import { createVNode, ref, computed } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined, QrcodeOutlined } 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';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<ShopDealerUser[]>([]);
// 当前编辑数据
const current = ref<ShopDealerUser | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示二维码弹窗
const showQrModal = ref(false);
const qrModalUrl = ref<string>('');
const qrModalTitle = ref<string>('二维码');
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
const getQrCodeUrl = (userId?: number) => {
return `https://mp-api.websoft.top/api/wx-login/getOrderQRCodeUnlimited/uid_${userId ?? ''}`;
};
const openQrCode = (row: ShopDealerUser) => {
if (!row.userId) {
message.warning('缺少用户ID无法生成二维码');
return;
}
qrModalUrl.value = getQrCodeUrl(row.userId);
qrModalTitle.value = row.realName ? `${row.realName} 的二维码` : `UID_${row.userId} 二维码`;
showQrModal.value = true;
};
const copyQrUrl = async () => {
if (!qrModalUrl.value) {
return;
}
try {
await navigator.clipboard.writeText(qrModalUrl.value);
message.success('已复制');
} catch (e) {
message.error('复制失败,请手动复制');
}
};
const openQrInNewTab = () => {
if (!qrModalUrl.value) {
return;
}
window.open(qrModalUrl.value, '_blank');
};
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
where.type = 2;
return pageShopDealerUser({
...where,
...orders,
page,
limit
});
};
// 完整的列配置(包含所有字段)
const columns = ref<ColumnItem[]>([
{
title: '用户ID',
dataIndex: 'userId',
key: 'userId',
width: 90,
},
{
title: '类型',
dataIndex: 'type',
key: 'type',
align: 'center',
width: 120
},
{
title: '所属门店',
dataIndex: 'shopName',
key: 'shopName'
},
{
title: '真实姓名',
dataIndex: 'realName',
key: 'realName'
},
{
title: '手机号',
dataIndex: 'mobile',
key: 'mobile'
},
// {
// title: '工资',
// dataIndex: 'money',
// key: 'money',
// width: 120
// },
// {
// title: '已冻结',
// dataIndex: 'freezeMoney',
// key: 'freezeMoney',
// width: 120
// },
{
title: '工资统计',
dataIndex: 'totalMoney',
key: 'totalMoney',
width: 120
},
// {
// title: '推荐人用户ID',
// dataIndex: 'refereeId',
// key: 'refereeId',
// width: 120
// },
// {
// title: '成员数量(一级)',
// dataIndex: 'firstNum',
// key: 'firstNum',
// width: 120
// },
// {
// title: '成员数量(二级)',
// dataIndex: 'secondNum',
// key: 'secondNum',
// width: 120
// },
// {
// title: '成员数量(三级)',
// dataIndex: 'thirdNum',
// key: 'thirdNum',
// width: 120
// },
// {
// title: '备注',
// dataIndex: 'comments',
// key: 'comments',
// ellipsis: true
// },
// {
// title: '排序号',
// dataIndex: 'sortNumber',
// key: 'sortNumber',
// width: 120
// },
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
width: 200,
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd HH:mm:ss')
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: ShopDealerUserParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: ShopDealerUser) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: ShopDealerUser) => {
const hide = message.loading('请求中..', 0);
removeShopDealerUser(row.id)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchShopDealerUser(selection.value.map((d) => d.id))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: ShopDealerUser) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'ShopDealerUser'
};
</script>
<style lang="less" scoped></style>