feat(shop): 新增首页专区管理功能
- 在商品模型中添加所属专区字段 sectionIds,支持逗号分隔字符串 - 商品编辑界面增加所属专区多选下拉框,联动专区数据 - 新增首页专区相关接口,包括分页查询、增删改查及权限校验等 - 实现首页专区列表页面,支持专区的增删改查及状态切换 - 新增专区白名单用户管理弹窗,支持多选用户设置白名单 - 实现专区商品列表抽屉,支持分页查看专区内商品 - 首页专区编辑弹窗支持标题、副标题、banner等多字段编辑及上传功能 - 完善专区管理界面交互和表格展示,支持搜索和状态筛选功能
This commit is contained in:
@@ -151,6 +151,8 @@ export interface ShopGoods {
|
|||||||
activityType?: number;
|
activityType?: number;
|
||||||
// 配送方式:0送上门 1限自提
|
// 配送方式:0送上门 1限自提
|
||||||
deliveryMode?: number;
|
deliveryMode?: number;
|
||||||
|
// 所属专区(逗号分隔的 sectionId 字符串,对应 shop_goods.section_ids 列)
|
||||||
|
sectionIds?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BathSet {
|
export interface BathSet {
|
||||||
|
|||||||
@@ -0,0 +1,156 @@
|
|||||||
|
import request from '@/utils/request';
|
||||||
|
import type { ApiResult, PageResult } from '@/api';
|
||||||
|
import type {
|
||||||
|
HomeSection,
|
||||||
|
HomeSectionParam,
|
||||||
|
SectionPermission,
|
||||||
|
SectionGoods,
|
||||||
|
SectionUser
|
||||||
|
} from './model';
|
||||||
|
import { MODULES_API_URL } from '@/config/setting';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询首页专区
|
||||||
|
*/
|
||||||
|
export async function pageHomeSections(params: HomeSectionParam) {
|
||||||
|
const res = await request.get<ApiResult<PageResult<HomeSection>>>(
|
||||||
|
MODULES_API_URL + '/shop/shop-home-section/page',
|
||||||
|
{
|
||||||
|
params
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
return res.data.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询首页专区列表
|
||||||
|
*/
|
||||||
|
export async function listHomeSections(params?: HomeSectionParam) {
|
||||||
|
const res = await request.get<ApiResult<HomeSection[]>>(
|
||||||
|
MODULES_API_URL + '/shop/shop-home-section',
|
||||||
|
{
|
||||||
|
params
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (res.data.code === 0 && res.data.data) {
|
||||||
|
return res.data.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据id查询首页专区
|
||||||
|
*/
|
||||||
|
export async function getHomeSection(id: number) {
|
||||||
|
const res = await request.get<ApiResult<HomeSection>>(
|
||||||
|
MODULES_API_URL + '/shop/shop-home-section/' + id
|
||||||
|
);
|
||||||
|
if (res.data.code === 0 && res.data.data) {
|
||||||
|
return res.data.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加首页专区
|
||||||
|
*/
|
||||||
|
export async function addHomeSection(data: HomeSection) {
|
||||||
|
const res = await request.post<ApiResult<unknown>>(
|
||||||
|
MODULES_API_URL + '/shop/shop-home-section',
|
||||||
|
data
|
||||||
|
);
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
return res.data.message;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改首页专区
|
||||||
|
*/
|
||||||
|
export async function updateHomeSection(data: HomeSection) {
|
||||||
|
const res = await request.put<ApiResult<unknown>>(
|
||||||
|
MODULES_API_URL + '/shop/shop-home-section',
|
||||||
|
data
|
||||||
|
);
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
return res.data.message;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除首页专区
|
||||||
|
*/
|
||||||
|
export async function removeHomeSection(id?: number) {
|
||||||
|
const res = await request.delete<ApiResult<unknown>>(
|
||||||
|
MODULES_API_URL + '/shop/shop-home-section/' + id
|
||||||
|
);
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
return res.data.message;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询专区白名单用户
|
||||||
|
*/
|
||||||
|
export async function listSectionUsers(id: number) {
|
||||||
|
const res = await request.get<ApiResult<SectionUser[]>>(
|
||||||
|
MODULES_API_URL + '/shop/shop-home-section/' + id + '/users'
|
||||||
|
);
|
||||||
|
if (res.data.code === 0 && res.data.data) {
|
||||||
|
return res.data.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存专区白名单用户(覆盖式)
|
||||||
|
*/
|
||||||
|
export async function setSectionUsers(id: number, userIds: number[]) {
|
||||||
|
const res = await request.put<ApiResult<unknown>>(
|
||||||
|
MODULES_API_URL + '/shop/shop-home-section/' + id + '/users',
|
||||||
|
userIds
|
||||||
|
);
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
return res.data.message;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询专区商品分页
|
||||||
|
*/
|
||||||
|
export async function listSectionGoods(
|
||||||
|
id: number,
|
||||||
|
params?: { page?: number; limit?: number }
|
||||||
|
) {
|
||||||
|
const res = await request.get<ApiResult<PageResult<SectionGoods>>>(
|
||||||
|
MODULES_API_URL + '/shop/shop-home-section/' + id + '/goods',
|
||||||
|
{
|
||||||
|
params: { page: 1, limit: 10, ...params }
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
return res.data.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验专区访问权限
|
||||||
|
*/
|
||||||
|
export async function checkSectionPermission(sectionIds: number[]) {
|
||||||
|
const res = await request.post<ApiResult<SectionPermission[]>>(
|
||||||
|
MODULES_API_URL + '/shop/shop-home-section/check-permission',
|
||||||
|
{ sectionIds }
|
||||||
|
);
|
||||||
|
if (res.data.code === 0 && res.data.data) {
|
||||||
|
return res.data.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
import type { PageParam } from '@/api';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 首页专区
|
||||||
|
*/
|
||||||
|
export interface HomeSection {
|
||||||
|
// 专区ID
|
||||||
|
sectionId?: number;
|
||||||
|
// 租户id
|
||||||
|
tenantId?: number;
|
||||||
|
// 专区标题
|
||||||
|
title?: string;
|
||||||
|
// 专区副标题
|
||||||
|
subtitle?: string;
|
||||||
|
// banner 图片URL
|
||||||
|
banner?: string;
|
||||||
|
// 关联分类ID(逗号分隔字符串,可选)
|
||||||
|
categoryIds?: string;
|
||||||
|
// 样式类型 0默认
|
||||||
|
styleType?: number;
|
||||||
|
// 是否受限专区 0否 1是
|
||||||
|
restricted?: number;
|
||||||
|
// 排序号(数字越小越靠前)
|
||||||
|
sortNumber?: number;
|
||||||
|
// 状态 0正常 1禁用
|
||||||
|
status?: number;
|
||||||
|
// 生效开始时间
|
||||||
|
startTime?: string;
|
||||||
|
// 生效结束时间
|
||||||
|
endTime?: string;
|
||||||
|
// 用户ID
|
||||||
|
userId?: number;
|
||||||
|
// 是否删除 0否 1是
|
||||||
|
deleted?: number;
|
||||||
|
// 创建时间
|
||||||
|
createTime?: string;
|
||||||
|
// 修改时间
|
||||||
|
updateTime?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 首页专区搜索条件
|
||||||
|
*/
|
||||||
|
export interface HomeSectionParam extends PageParam {
|
||||||
|
// 专区标题(模糊)
|
||||||
|
title?: string;
|
||||||
|
// 状态 0正常 1禁用
|
||||||
|
status?: number;
|
||||||
|
// 是否受限专区 0/1
|
||||||
|
restricted?: number;
|
||||||
|
// 排序号
|
||||||
|
sortNumber?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 专区权限校验结果
|
||||||
|
*/
|
||||||
|
export interface SectionPermission {
|
||||||
|
// 专区ID
|
||||||
|
sectionId?: number;
|
||||||
|
// 是否受限专区
|
||||||
|
restricted?: boolean;
|
||||||
|
// 当前用户是否允许访问
|
||||||
|
allowed?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 专区商品(只读展示,字段按需取用)
|
||||||
|
*/
|
||||||
|
export interface SectionGoods {
|
||||||
|
goodsId?: number;
|
||||||
|
name?: string;
|
||||||
|
image?: string;
|
||||||
|
price?: string;
|
||||||
|
salePrice?: string;
|
||||||
|
stock?: number;
|
||||||
|
status?: number;
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 专区白名单用户
|
||||||
|
*/
|
||||||
|
export interface SectionUser {
|
||||||
|
id?: number;
|
||||||
|
sectionId?: number;
|
||||||
|
userId?: number;
|
||||||
|
}
|
||||||
@@ -48,6 +48,17 @@
|
|||||||
@change="onCategoryIds"
|
@change="onCategoryIds"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<a-form-item label="所属专区" name="sectionIds">
|
||||||
|
<a-select
|
||||||
|
v-model:value="sectionIdList"
|
||||||
|
mode="multiple"
|
||||||
|
:max-tag-count="3"
|
||||||
|
:options="zoneOptions"
|
||||||
|
style="width: 320px"
|
||||||
|
placeholder="请选择所属专区(可多选)"
|
||||||
|
allow-clear
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
<a-form-item label="商品编码" name="code">
|
<a-form-item label="商品编码" name="code">
|
||||||
<a-input
|
<a-input
|
||||||
allow-clear
|
allow-clear
|
||||||
@@ -709,6 +720,7 @@ import {ShopExpressTemplate} from '@/api/shop/shopExpressTemplate/model';
|
|||||||
import {listShopExpressTemplate} from '@/api/shop/shopExpressTemplate';
|
import {listShopExpressTemplate} from '@/api/shop/shopExpressTemplate';
|
||||||
import {listShopCommissionRole} from '@/api/shop/shopCommissionRole';
|
import {listShopCommissionRole} from '@/api/shop/shopCommissionRole';
|
||||||
import {listShopGoodsRoleCommission} from '@/api/shop/shopGoodsRoleCommission';
|
import {listShopGoodsRoleCommission} from '@/api/shop/shopGoodsRoleCommission';
|
||||||
|
import {listHomeSections} from '@/api/shop/shopZone';
|
||||||
|
|
||||||
// 是否是修改
|
// 是否是修改
|
||||||
const isUpdate = ref(false);
|
const isUpdate = ref(false);
|
||||||
@@ -859,6 +871,9 @@ const skuList = ref<ShopGoodsSku[]>([]);
|
|||||||
const files = ref<ItemType[]>([]);
|
const files = ref<ItemType[]>([]);
|
||||||
const goodsSpec = ref<ShopGoodsSpec>();
|
const goodsSpec = ref<ShopGoodsSpec>();
|
||||||
const category = ref<string[]>([]);
|
const category = ref<string[]>([]);
|
||||||
|
// 所属专区(多选)
|
||||||
|
const sectionIdList = ref<number[]>([]);
|
||||||
|
const zoneOptions = ref<{ label: string; value: number }[]>([]);
|
||||||
|
|
||||||
// 批量设置
|
// 批量设置
|
||||||
const batchPrice = ref<number | undefined>(undefined);
|
const batchPrice = ref<number | undefined>(undefined);
|
||||||
@@ -1803,6 +1818,10 @@ const save = () => {
|
|||||||
|
|
||||||
const formData: any = {
|
const formData: any = {
|
||||||
...form,
|
...form,
|
||||||
|
// 所属专区:数字数组 -> 逗号分隔字符串
|
||||||
|
sectionIds: sectionIdList.value.length
|
||||||
|
? sectionIdList.value.join(',')
|
||||||
|
: '',
|
||||||
content: content.value,
|
content: content.value,
|
||||||
category: JSON.stringify(category.value),
|
category: JSON.stringify(category.value),
|
||||||
files: JSON.stringify(files.value),
|
files: JSON.stringify(files.value),
|
||||||
@@ -1966,8 +1985,20 @@ watch(
|
|||||||
async (visible) => {
|
async (visible) => {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
await getExpressTemplateList();
|
await getExpressTemplateList();
|
||||||
|
// 加载所属专区选项
|
||||||
|
listHomeSections({})
|
||||||
|
.then((list) => {
|
||||||
|
zoneOptions.value = (list || []).map((z) => ({
|
||||||
|
label: z.title || '',
|
||||||
|
value: z.sectionId as number
|
||||||
|
}));
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
zoneOptions.value = [];
|
||||||
|
});
|
||||||
|
|
||||||
images.value = [];
|
images.value = [];
|
||||||
|
sectionIdList.value = [];
|
||||||
category.value = [];
|
category.value = [];
|
||||||
files.value = [];
|
files.value = [];
|
||||||
videos.value = [];
|
videos.value = [];
|
||||||
@@ -1976,6 +2007,13 @@ watch(
|
|||||||
ensureTagItem.value = '';
|
ensureTagItem.value = '';
|
||||||
if (props.data) {
|
if (props.data) {
|
||||||
assignObject(form, props.data);
|
assignObject(form, props.data);
|
||||||
|
// 所属专区:逗号分隔字符串 -> 数字数组
|
||||||
|
sectionIdList.value = form.sectionIds
|
||||||
|
? form.sectionIds
|
||||||
|
.split(',')
|
||||||
|
.map((s) => Number(s.trim()))
|
||||||
|
.filter((n) => !Number.isNaN(n))
|
||||||
|
: [];
|
||||||
if (form.commissionType === undefined || form.commissionType === null) {
|
if (form.commissionType === undefined || form.commissionType === null) {
|
||||||
form.commissionType = 10;
|
form.commissionType = 10;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -0,0 +1,251 @@
|
|||||||
|
<!-- 首页专区编辑弹窗 -->
|
||||||
|
<template>
|
||||||
|
<ele-modal
|
||||||
|
:width="640"
|
||||||
|
:visible="visible"
|
||||||
|
:maskClosable="false"
|
||||||
|
:title="isUpdate ? '编辑专区' : '添加专区'"
|
||||||
|
:body-style="{ paddingBottom: '28px' }"
|
||||||
|
@update:visible="updateVisible"
|
||||||
|
@ok="save"
|
||||||
|
>
|
||||||
|
<a-form
|
||||||
|
ref="formRef"
|
||||||
|
:model="form"
|
||||||
|
:rules="rules"
|
||||||
|
:label-col="{ flex: '90px' }"
|
||||||
|
:wrapper-col="{ flex: '1' }"
|
||||||
|
>
|
||||||
|
<a-form-item label="专区标题" name="title">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入专区标题"
|
||||||
|
v-model:value="form.title"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="副标题" name="subtitle">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="可选,专区副标题"
|
||||||
|
v-model:value="form.subtitle"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="banner图" name="banner">
|
||||||
|
<a-upload
|
||||||
|
:before-upload="handleBannerUpload"
|
||||||
|
:show-upload-list="false"
|
||||||
|
accept="image/*"
|
||||||
|
>
|
||||||
|
<a-button v-if="!form.banner">
|
||||||
|
<template #icon><UploadOutlined /></template>
|
||||||
|
上传 banner
|
||||||
|
</a-button>
|
||||||
|
<div v-else class="flex items-center gap-2">
|
||||||
|
<img :src="form.banner" style="width: 120px; height: 48px; object-fit: cover; border-radius: 4px; border: 1px solid #d9d9d9;" />
|
||||||
|
<a-button type="text" danger size="small" @click.stop="form.banner = undefined">删除</a-button>
|
||||||
|
</div>
|
||||||
|
</a-upload>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="关联分类" name="categoryIds">
|
||||||
|
<a-input
|
||||||
|
allow-clear
|
||||||
|
placeholder="可选,分类ID逗号分隔,如:1,2,3"
|
||||||
|
v-model:value="form.categoryIds"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="样式类型" name="styleType">
|
||||||
|
<a-input-number
|
||||||
|
:min="0"
|
||||||
|
:max="99"
|
||||||
|
style="width: 100%"
|
||||||
|
placeholder="默认0"
|
||||||
|
v-model:value="form.styleType"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="是否受限" name="restricted">
|
||||||
|
<a-switch
|
||||||
|
size="small"
|
||||||
|
v-model:checked="form.restricted"
|
||||||
|
:checked-value="1"
|
||||||
|
:un-checked-value="0"
|
||||||
|
checked-children="受限专区"
|
||||||
|
un-checked-children="普通专区"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="排序号" name="sortNumber">
|
||||||
|
<a-input-number
|
||||||
|
:min="0"
|
||||||
|
:max="9999"
|
||||||
|
style="width: 100%"
|
||||||
|
placeholder="数值越小越靠前"
|
||||||
|
v-model:value="form.sortNumber"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="状态" name="status">
|
||||||
|
<a-switch
|
||||||
|
size="small"
|
||||||
|
v-model:checked="form.status"
|
||||||
|
:checked-value="0"
|
||||||
|
:un-checked-value="1"
|
||||||
|
checked-children="正常"
|
||||||
|
un-checked-children="禁用"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="生效开始" name="startTime">
|
||||||
|
<a-date-picker
|
||||||
|
show-time
|
||||||
|
style="width: 100%"
|
||||||
|
value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
placeholder="可选,专区生效开始时间"
|
||||||
|
:value="form.startTime || undefined"
|
||||||
|
@update:value="(val: any) => (form.startTime = val || undefined)"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="生效结束" name="endTime">
|
||||||
|
<a-date-picker
|
||||||
|
show-time
|
||||||
|
style="width: 100%"
|
||||||
|
value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
placeholder="可选,专区生效结束时间"
|
||||||
|
:value="form.endTime || undefined"
|
||||||
|
@update:value="(val: any) => (form.endTime = val || undefined)"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</ele-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, reactive, watch } from 'vue';
|
||||||
|
import { message } from 'ant-design-vue';
|
||||||
|
import { UploadOutlined } from '@ant-design/icons-vue';
|
||||||
|
import { assignObject } from 'ele-admin-pro';
|
||||||
|
import { addHomeSection, updateHomeSection } from '@/api/shop/shopZone';
|
||||||
|
import { uploadFile } from '@/api/system/file';
|
||||||
|
import type { HomeSection } from '@/api/shop/shopZone/model';
|
||||||
|
import type { FormInstance } from 'ant-design-vue/es/form';
|
||||||
|
|
||||||
|
const isUpdate = ref(false);
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
visible: boolean;
|
||||||
|
data?: HomeSection | null;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'done'): void;
|
||||||
|
(e: 'update:visible', visible: boolean): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const loading = ref(false);
|
||||||
|
const formRef = ref<FormInstance | null>(null);
|
||||||
|
|
||||||
|
const form = reactive<HomeSection>({
|
||||||
|
sectionId: undefined,
|
||||||
|
tenantId: undefined,
|
||||||
|
title: undefined,
|
||||||
|
subtitle: undefined,
|
||||||
|
banner: undefined,
|
||||||
|
categoryIds: undefined,
|
||||||
|
styleType: 0,
|
||||||
|
restricted: 0,
|
||||||
|
sortNumber: 100,
|
||||||
|
status: 0,
|
||||||
|
startTime: undefined,
|
||||||
|
endTime: undefined,
|
||||||
|
userId: undefined,
|
||||||
|
deleted: 0,
|
||||||
|
createTime: undefined,
|
||||||
|
updateTime: undefined
|
||||||
|
});
|
||||||
|
|
||||||
|
const updateVisible = (value: boolean) => {
|
||||||
|
emit('update:visible', value);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 表单验证规则
|
||||||
|
const rules: Record<string, any> = {
|
||||||
|
title: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
type: 'string',
|
||||||
|
message: '请输入专区标题',
|
||||||
|
trigger: 'blur'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const save = () => {
|
||||||
|
if (!formRef.value) return;
|
||||||
|
formRef.value
|
||||||
|
.validate()
|
||||||
|
.then(() => {
|
||||||
|
loading.value = true;
|
||||||
|
const saveOrUpdate = isUpdate.value ? updateHomeSection : addHomeSection;
|
||||||
|
saveOrUpdate({ ...form })
|
||||||
|
.then((msg) => {
|
||||||
|
loading.value = false;
|
||||||
|
message.success(msg);
|
||||||
|
updateVisible(false);
|
||||||
|
emit('done');
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
loading.value = false;
|
||||||
|
message.error(e.message);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
|
};
|
||||||
|
|
||||||
|
// banner 上传
|
||||||
|
const handleBannerUpload = async (file: File) => {
|
||||||
|
const isImage = file.type?.startsWith('image/');
|
||||||
|
if (!isImage) {
|
||||||
|
message.error('只能上传图片文件');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const res = await uploadFile(file);
|
||||||
|
if (res?.path) {
|
||||||
|
form.banner = res.path;
|
||||||
|
}
|
||||||
|
} catch (e: any) {
|
||||||
|
message.error(e.message || '上传失败');
|
||||||
|
}
|
||||||
|
return false; // 阻止默认上传
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.visible,
|
||||||
|
(visible) => {
|
||||||
|
if (visible) {
|
||||||
|
if (props.data) {
|
||||||
|
assignObject(form, props.data);
|
||||||
|
isUpdate.value = true;
|
||||||
|
} else {
|
||||||
|
Object.assign(form, {
|
||||||
|
sectionId: undefined,
|
||||||
|
tenantId: undefined,
|
||||||
|
title: undefined,
|
||||||
|
subtitle: undefined,
|
||||||
|
banner: undefined,
|
||||||
|
categoryIds: undefined,
|
||||||
|
styleType: 0,
|
||||||
|
restricted: 0,
|
||||||
|
sortNumber: 100,
|
||||||
|
status: 0,
|
||||||
|
startTime: undefined,
|
||||||
|
endTime: undefined
|
||||||
|
});
|
||||||
|
isUpdate.value = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
formRef.value?.resetFields();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,380 @@
|
|||||||
|
<!-- 首页专区管理 -->
|
||||||
|
<template>
|
||||||
|
<div class="page">
|
||||||
|
<div class="ele-body">
|
||||||
|
<a-card :bordered="false" :body-style="{ padding: '16px' }">
|
||||||
|
<ele-pro-table
|
||||||
|
ref="tableRef"
|
||||||
|
row-key="sectionId"
|
||||||
|
:columns="columns"
|
||||||
|
:datasource="datasource"
|
||||||
|
:customRow="customRow"
|
||||||
|
tool-class="ele-toolbar-form"
|
||||||
|
class="sys-org-table"
|
||||||
|
>
|
||||||
|
<template #toolbar>
|
||||||
|
<a-space :size="10" style="flex-wrap: wrap">
|
||||||
|
<a-input-search
|
||||||
|
v-model:value="where.title"
|
||||||
|
placeholder="搜索专区标题"
|
||||||
|
allow-clear
|
||||||
|
style="width: 200px"
|
||||||
|
@search="() => reload()"
|
||||||
|
@pressEnter="() => reload()"
|
||||||
|
/>
|
||||||
|
<a-select
|
||||||
|
v-model:value="where.status"
|
||||||
|
placeholder="状态"
|
||||||
|
allow-clear
|
||||||
|
style="width: 120px"
|
||||||
|
@change="() => reload()"
|
||||||
|
>
|
||||||
|
<a-select-option :value="0">正常</a-select-option>
|
||||||
|
<a-select-option :value="1">禁用</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
<a-button type="primary" class="ele-btn-icon" @click="openEdit()">
|
||||||
|
<template #icon><PlusOutlined /></template>
|
||||||
|
<span>添加专区</span>
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === 'banner'">
|
||||||
|
<img
|
||||||
|
v-if="record.banner"
|
||||||
|
:src="getCompressedImageUrl(record.banner, { width: 96, quality: 85 })"
|
||||||
|
style="max-width: 80px; height: 32px; object-fit: cover; border-radius: 4px;"
|
||||||
|
/>
|
||||||
|
<span v-else>-</span>
|
||||||
|
</template>
|
||||||
|
<template v-if="column.key === 'restricted'">
|
||||||
|
<a-tag :color="record.restricted === 1 ? 'red' : 'default'">
|
||||||
|
{{ record.restricted === 1 ? '受限专区' : '普通专区' }}
|
||||||
|
</a-tag>
|
||||||
|
</template>
|
||||||
|
<template v-if="column.key === 'status'">
|
||||||
|
<a-switch
|
||||||
|
:checked="record.status === 0"
|
||||||
|
checked-children="正常"
|
||||||
|
un-checked-children="禁用"
|
||||||
|
size="small"
|
||||||
|
@change="(val: boolean) => toggleStatus(record, val)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template v-if="column.key === 'action'">
|
||||||
|
<a-space>
|
||||||
|
<a @click="openEdit(record)">编辑</a>
|
||||||
|
<a-divider type="vertical" />
|
||||||
|
<a @click="openUsers(record)">白名单</a>
|
||||||
|
<a-divider type="vertical" />
|
||||||
|
<a @click="openGoods(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>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 编辑弹窗 -->
|
||||||
|
<ZoneEdit v-model:visible="showEdit" :data="current" @done="reload" />
|
||||||
|
|
||||||
|
<!-- 白名单用户选择弹窗 -->
|
||||||
|
<UserSelectModal
|
||||||
|
v-model:visible="showUser"
|
||||||
|
:sectionId="currentSectionId"
|
||||||
|
:selectedUserIds="currentUserIds"
|
||||||
|
@confirm="onSaveUsers"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 专区商品抽屉 -->
|
||||||
|
<a-drawer
|
||||||
|
:width="800"
|
||||||
|
:visible="showGoods"
|
||||||
|
title="专区商品"
|
||||||
|
:maskClosable="false"
|
||||||
|
@update:visible="(v: boolean) => (showGoods = v)"
|
||||||
|
>
|
||||||
|
<a-empty v-if="goodsLoading" description="加载中..." />
|
||||||
|
<template v-else>
|
||||||
|
<a-table
|
||||||
|
row-key="goodsId"
|
||||||
|
:dataSource="goodsList"
|
||||||
|
:columns="goodsColumns"
|
||||||
|
:pagination="{
|
||||||
|
total: goodsTotal,
|
||||||
|
current: goodsPage,
|
||||||
|
pageSize: 10,
|
||||||
|
onChange: (page: number) => {
|
||||||
|
goodsPage = page;
|
||||||
|
loadGoods(currentSectionId);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
:scroll="{ y: 480 }"
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, text }">
|
||||||
|
<template v-if="column.key === 'image'">
|
||||||
|
<img
|
||||||
|
v-if="text"
|
||||||
|
:src="text"
|
||||||
|
style="width: 48px; height: 48px; object-fit: cover; border-radius: 4px;"
|
||||||
|
/>
|
||||||
|
<span v-else>-</span>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
</template>
|
||||||
|
</a-drawer>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { message } from 'ant-design-vue';
|
||||||
|
import { PlusOutlined } 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 ZoneEdit from './components/zoneEdit.vue';
|
||||||
|
import UserSelectModal from './components/UserSelectModal.vue';
|
||||||
|
import { getCompressedImageUrl } from '@/utils/image';
|
||||||
|
import {
|
||||||
|
pageHomeSections,
|
||||||
|
removeHomeSection,
|
||||||
|
updateHomeSection,
|
||||||
|
listSectionUsers,
|
||||||
|
setSectionUsers,
|
||||||
|
listSectionGoods
|
||||||
|
} from '@/api/shop/shopZone';
|
||||||
|
import type {
|
||||||
|
HomeSection,
|
||||||
|
HomeSectionParam
|
||||||
|
} from '@/api/shop/shopZone/model';
|
||||||
|
|
||||||
|
// 表格实例
|
||||||
|
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
|
||||||
|
|
||||||
|
// 当前编辑数据
|
||||||
|
const current = ref<HomeSection | null>(null);
|
||||||
|
// 是否显示编辑弹窗
|
||||||
|
const showEdit = ref(false);
|
||||||
|
|
||||||
|
// 白名单弹窗
|
||||||
|
const showUser = ref(false);
|
||||||
|
const currentSectionId = ref<number>(0);
|
||||||
|
const currentUserIds = ref<number[]>([]);
|
||||||
|
|
||||||
|
// 商品抽屉
|
||||||
|
const showGoods = ref(false);
|
||||||
|
const goodsLoading = ref(false);
|
||||||
|
const goodsList = ref<any[]>([]);
|
||||||
|
const goodsTotal = ref(0);
|
||||||
|
const goodsPage = ref(1);
|
||||||
|
|
||||||
|
// 表格数据源
|
||||||
|
const datasource: DatasourceFunction = ({ page, limit, where, orders }) => {
|
||||||
|
return pageHomeSections({
|
||||||
|
...where,
|
||||||
|
...orders,
|
||||||
|
page,
|
||||||
|
limit
|
||||||
|
}).then((res) => {
|
||||||
|
return { list: res?.list || [], count: res?.count || 0 };
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 表格列配置
|
||||||
|
const columns = ref<ColumnItem[]>([
|
||||||
|
{
|
||||||
|
title: 'ID',
|
||||||
|
dataIndex: 'sectionId',
|
||||||
|
key: 'sectionId',
|
||||||
|
align: 'center',
|
||||||
|
width: 70
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '专区标题',
|
||||||
|
dataIndex: 'title',
|
||||||
|
key: 'title',
|
||||||
|
align: 'left',
|
||||||
|
minWidth: 160
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'banner',
|
||||||
|
dataIndex: 'banner',
|
||||||
|
key: 'banner',
|
||||||
|
align: 'center',
|
||||||
|
width: 110
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '是否受限',
|
||||||
|
dataIndex: 'restricted',
|
||||||
|
key: 'restricted',
|
||||||
|
align: 'center',
|
||||||
|
width: 110
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '排序',
|
||||||
|
dataIndex: 'sortNumber',
|
||||||
|
key: 'sortNumber',
|
||||||
|
align: 'center',
|
||||||
|
width: 80,
|
||||||
|
sorter: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '状态',
|
||||||
|
dataIndex: 'status',
|
||||||
|
key: 'status',
|
||||||
|
align: 'center',
|
||||||
|
width: 90
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '创建时间',
|
||||||
|
dataIndex: 'createTime',
|
||||||
|
key: 'createTime',
|
||||||
|
align: 'center',
|
||||||
|
width: 120,
|
||||||
|
sorter: true,
|
||||||
|
customRender: ({ text }: any) => toDateString(text, 'yyyy-MM-dd')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
key: 'action',
|
||||||
|
width: 220,
|
||||||
|
fixed: 'right',
|
||||||
|
align: 'center',
|
||||||
|
hideInSetting: true
|
||||||
|
}
|
||||||
|
] as unknown as ColumnItem[]);
|
||||||
|
|
||||||
|
// 商品表格列
|
||||||
|
const goodsColumns = [
|
||||||
|
{ title: 'ID', dataIndex: 'goodsId', key: 'goodsId', align: 'center', width: 70 },
|
||||||
|
{ title: '商品名称', dataIndex: 'name', key: 'name', align: 'left' },
|
||||||
|
{
|
||||||
|
title: '图片',
|
||||||
|
dataIndex: 'image',
|
||||||
|
key: 'image',
|
||||||
|
align: 'center',
|
||||||
|
width: 90
|
||||||
|
},
|
||||||
|
{ title: '商城价', dataIndex: 'price', key: 'price', align: 'center', width: 100 },
|
||||||
|
{ title: '库存', dataIndex: 'stock', key: 'stock', align: 'center', width: 90 }
|
||||||
|
] as any[];
|
||||||
|
|
||||||
|
/* 搜索条件 */
|
||||||
|
const where = ref<HomeSectionParam>({
|
||||||
|
title: '',
|
||||||
|
status: undefined,
|
||||||
|
restricted: undefined,
|
||||||
|
sortNumber: undefined
|
||||||
|
});
|
||||||
|
|
||||||
|
/* 搜索 */
|
||||||
|
const reload = (w?: HomeSectionParam) => {
|
||||||
|
if (w) {
|
||||||
|
where.value = { ...where.value, ...w };
|
||||||
|
}
|
||||||
|
tableRef?.value?.reload({ where: where.value });
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 打开编辑弹窗 */
|
||||||
|
const openEdit = (row?: HomeSection) => {
|
||||||
|
current.value = row ?? null;
|
||||||
|
showEdit.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 切换状态 */
|
||||||
|
const toggleStatus = (row: HomeSection, val: boolean) => {
|
||||||
|
const newStatus = val ? 0 : 1;
|
||||||
|
updateHomeSection({ ...row, status: newStatus })
|
||||||
|
.then((msg) => {
|
||||||
|
message.success(msg);
|
||||||
|
row.status = newStatus;
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
message.error(e.message);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 删除单个 */
|
||||||
|
const remove = (row: HomeSection) => {
|
||||||
|
const hide = message.loading('请求中..', 0);
|
||||||
|
removeHomeSection(row.sectionId)
|
||||||
|
.then((msg) => {
|
||||||
|
hide();
|
||||||
|
message.success(msg);
|
||||||
|
reload();
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
hide();
|
||||||
|
message.error(e.message);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 打开白名单弹窗 */
|
||||||
|
const openUsers = (row: HomeSection) => {
|
||||||
|
currentSectionId.value = row.sectionId || 0;
|
||||||
|
listSectionUsers(row.sectionId || 0)
|
||||||
|
.then((list) => {
|
||||||
|
currentUserIds.value = (list || []).map((u) => u.userId || 0).filter(Boolean);
|
||||||
|
showUser.value = true;
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
message.error(e.message);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 保存白名单 */
|
||||||
|
const onSaveUsers = (userIds: number[]) => {
|
||||||
|
setSectionUsers(currentSectionId.value, userIds)
|
||||||
|
.then((msg) => {
|
||||||
|
message.success(msg || '白名单已保存');
|
||||||
|
showUser.value = false;
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
message.error(e.message);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 打开商品抽屉 */
|
||||||
|
const openGoods = (row: HomeSection) => {
|
||||||
|
currentSectionId.value = row.sectionId || 0;
|
||||||
|
goodsPage.value = 1;
|
||||||
|
showGoods.value = true;
|
||||||
|
loadGoods(row.sectionId || 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadGoods = (sectionId: number) => {
|
||||||
|
goodsLoading.value = true;
|
||||||
|
listSectionGoods(sectionId, { page: goodsPage.value, limit: 10 })
|
||||||
|
.then((res) => {
|
||||||
|
goodsList.value = res?.list || [];
|
||||||
|
goodsTotal.value = res?.count || 0;
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
message.error(e.message);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
goodsLoading.value = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 行属性:双击编辑 */
|
||||||
|
const customRow = (record: HomeSection) => {
|
||||||
|
return {
|
||||||
|
onDblclick: () => {
|
||||||
|
openEdit(record);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
</script>
|
||||||
Reference in New Issue
Block a user