feat(shop): 新增首页专区管理功能

- 在商品模型中添加所属专区字段 sectionIds,支持逗号分隔字符串
- 商品编辑界面增加所属专区多选下拉框,联动专区数据
- 新增首页专区相关接口,包括分页查询、增删改查及权限校验等
- 实现首页专区列表页面,支持专区的增删改查及状态切换
- 新增专区白名单用户管理弹窗,支持多选用户设置白名单
- 实现专区商品列表抽屉,支持分页查看专区内商品
- 首页专区编辑弹窗支持标题、副标题、banner等多字段编辑及上传功能
- 完善专区管理界面交互和表格展示,支持搜索和状态筛选功能
This commit is contained in:
2026-08-15 03:30:48 +08:00
parent 053b776d9a
commit b5c67988a6
7 changed files with 1076 additions and 0 deletions
@@ -0,0 +1,161 @@
<!-- 白名单用户多选弹窗 -->
<template>
<ele-modal
:width="820"
:visible="visible"
:maskClosable="false"
title="设置专区白名单用户"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="confirm"
>
<ele-pro-table
ref="tableRef"
row-key="userId"
:datasource="datasource"
:columns="columns"
:row-selection="rowSelection"
:pagination="true"
:page-size="10"
>
<template #toolbar>
<a-space>
<a-input-search
allow-clear
v-model:value="searchText"
placeholder="姓名/手机号/昵称"
style="width: 220px"
@search="reload"
@pressEnter="reload"
/>
</a-space>
</template>
</ele-pro-table>
<div class="mt-2 ele-text-secondary">
已选 {{ rowSelection.selectedRowKeys.length }}
</div>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import {
ColumnItem,
DatasourceFunction
} from 'ele-admin-pro/es/ele-pro-table/types';
import { pageUsers } from '@/api/system/user';
import { EleProTable } from 'ele-admin-pro';
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 专区ID
sectionId?: number;
// 已选用户ID
selectedUserIds?: number[];
}>();
const emit = defineEmits<{
(e: 'confirm', userIds: number[]): void;
(e: 'update:visible', visible: boolean): void;
}>();
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 搜索内容
const searchText = ref<string>('');
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格配置
const columns = ref<ColumnItem[]>([
{
title: 'ID',
dataIndex: 'userId',
key: 'userId',
align: 'center',
width: 80
},
{
title: '姓名',
dataIndex: 'realName',
key: 'realName',
align: 'center'
},
{
title: '手机号码',
dataIndex: 'mobile',
key: 'mobile',
align: 'center'
},
{
title: '昵称',
dataIndex: 'nickname',
key: 'nickname',
align: 'center'
},
{
title: '所属部门',
dataIndex: 'organizationName',
key: 'organizationName',
align: 'center'
}
]);
// 多选配置
const rowSelection = reactive({
type: 'checkbox' as const,
selectedRowKeys: [] as number[],
onChange: (keys: (string | number)[]) => {
rowSelection.selectedRowKeys = keys.map((k) => Number(k));
}
});
// 表格数据源
const datasource: DatasourceFunction = ({ page, limit, where, orders }) => {
if (searchText.value) {
where.keywords = searchText.value;
}
return pageUsers({
isStaff: true,
keywords: searchText.value,
...where,
...orders,
page,
limit
});
};
/* 搜索 */
const reload = () => {
tableRef?.value?.reload({ page: 1 });
};
/* 确认保存 */
const confirm = () => {
emit('confirm', [...rowSelection.selectedRowKeys]);
updateVisible(false);
};
// 打开弹窗时初始化已选
watch(
() => props.visible,
(visible) => {
if (visible) {
rowSelection.selectedRowKeys = props.selectedUserIds
? [...props.selectedUserIds]
: [];
if (tableRef.value) {
// 等待表格挂载后刷新
setTimeout(() => reload(), 0);
}
}
},
{ immediate: true }
);
</script>
<style lang="less"></style>