Merge remote-tracking branch 'origin/dev' into dev

# Conflicts:
#	apps/web-antd/src/views/mall/promotion/point/activity/data.ts
#	apps/web-antd/src/views/mall/promotion/point/activity/index.vue
This commit is contained in:
YunaiV
2025-10-23 12:46:02 +08:00
31 changed files with 176 additions and 136 deletions

View File

@@ -18,7 +18,8 @@ const routes: RouteRecordRaw[] = [
title: '产品详情', title: '产品详情',
activePath: '/iot/device/product', activePath: '/iot/device/product',
}, },
component: () => import('#/views/iot/product/product/modules/detail/index.vue'), component: () =>
import('#/views/iot/product/product/modules/detail/index.vue'),
}, },
{ {
path: 'device/detail/:id', path: 'device/detail/:id',
@@ -27,7 +28,8 @@ const routes: RouteRecordRaw[] = [
title: '设备详情', title: '设备详情',
activePath: '/iot/device/device', activePath: '/iot/device/device',
}, },
component: () => import('#/views/iot/device/device/modules/detail/index.vue'), component: () =>
import('#/views/iot/device/device/modules/detail/index.vue'),
}, },
{ {
path: 'ota/firmware/detail/:id', path: 'ota/firmware/detail/:id',
@@ -36,11 +38,11 @@ const routes: RouteRecordRaw[] = [
title: '固件详情', title: '固件详情',
activePath: '/iot/ota', activePath: '/iot/ota',
}, },
component: () => import('#/views/iot/ota/modules/firmware-detail/index.vue'), component: () =>
import('#/views/iot/ota/modules/firmware-detail/index.vue'),
}, },
], ],
}, },
]; ];
export default routes; export default routes;

View File

@@ -26,7 +26,7 @@ const [Grid] = useVbenVxeGrid({
{ {
fieldName: 'followUpStatus', fieldName: 'followUpStatus',
label: '状态', label: '状态',
component: 'Select', component: 'RadioGroup',
componentProps: { componentProps: {
allowClear: true, allowClear: true,
options: FOLLOWUP_STATUS, options: FOLLOWUP_STATUS,

View File

@@ -26,7 +26,7 @@ const [Grid] = useVbenVxeGrid({
{ {
fieldName: 'followUpStatus', fieldName: 'followUpStatus',
label: '状态', label: '状态',
component: 'Select', component: 'RadioGroup',
componentProps: { componentProps: {
allowClear: true, allowClear: true,
options: FOLLOWUP_STATUS, options: FOLLOWUP_STATUS,

View File

@@ -171,7 +171,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
{ {
fieldName: 'transformStatus', fieldName: 'transformStatus',
label: '转化状态', label: '转化状态',
component: 'Select', component: 'RadioGroup',
componentProps: { componentProps: {
options: [ options: [
{ label: '未转化', value: false }, { label: '未转化', value: false },

View File

@@ -76,7 +76,7 @@ export function useFormSchema(): VbenFormSchema[] {
label: '接收的用户', label: '接收的用户',
component: 'ApiSelect', component: 'ApiSelect',
componentProps: { componentProps: {
api: () => getSimpleUserList(), api: getSimpleUserList,
labelField: 'nickname', labelField: 'nickname',
valueField: 'id', valueField: 'id',
mode: 'multiple', mode: 'multiple',
@@ -124,7 +124,10 @@ export function useGridFormSchema(): VbenFormSchema[] {
fieldName: 'createTime', fieldName: 'createTime',
label: '创建时间', label: '创建时间',
component: 'RangePicker', component: 'RangePicker',
componentProps: getRangePickerDefaultProps(), componentProps: {
...getRangePickerDefaultProps(),
allowClear: true,
},
}, },
]; ];
} }

View File

@@ -17,7 +17,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
label: '告警配置', label: '告警配置',
component: 'ApiSelect', component: 'ApiSelect',
componentProps: { componentProps: {
api: () => getSimpleAlertConfigList(), api: getSimpleAlertConfigList,
labelField: 'name', labelField: 'name',
valueField: 'id', valueField: 'id',
placeholder: '请选择告警配置', placeholder: '请选择告警配置',
@@ -40,7 +40,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
label: '产品', label: '产品',
component: 'ApiSelect', component: 'ApiSelect',
componentProps: { componentProps: {
api: () => getSimpleProductList(), api: getSimpleProductList,
labelField: 'name', labelField: 'name',
valueField: 'id', valueField: 'id',
placeholder: '请选择产品', placeholder: '请选择产品',
@@ -53,7 +53,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
label: '设备', label: '设备',
component: 'ApiSelect', component: 'ApiSelect',
componentProps: { componentProps: {
api: () => getSimpleDeviceList(), api: getSimpleDeviceList,
labelField: 'deviceName', labelField: 'deviceName',
valueField: 'id', valueField: 'id',
placeholder: '请选择设备', placeholder: '请选择设备',
@@ -75,7 +75,10 @@ export function useGridFormSchema(): VbenFormSchema[] {
fieldName: 'createTime', fieldName: 'createTime',
label: '创建时间', label: '创建时间',
component: 'RangePicker', component: 'RangePicker',
componentProps: getRangePickerDefaultProps(), componentProps: {
...getRangePickerDefaultProps(),
allowClear: true,
},
}, },
]; ];
} }

View File

@@ -28,7 +28,7 @@ export function useFormSchema(): VbenFormSchema[] {
label: '产品', label: '产品',
component: 'ApiSelect', component: 'ApiSelect',
componentProps: { componentProps: {
api: () => getSimpleProductList(), api: getSimpleProductList,
labelField: 'name', labelField: 'name',
valueField: 'id', valueField: 'id',
placeholder: '请选择产品', placeholder: '请选择产品',
@@ -89,7 +89,7 @@ export function useFormSchema(): VbenFormSchema[] {
label: '设备分组', label: '设备分组',
component: 'ApiSelect', component: 'ApiSelect',
componentProps: { componentProps: {
api: () => getSimpleDeviceGroupList(), api: getSimpleDeviceGroupList,
labelField: 'name', labelField: 'name',
valueField: 'id', valueField: 'id',
mode: 'multiple', mode: 'multiple',
@@ -156,7 +156,7 @@ export function useGroupFormSchema(): VbenFormSchema[] {
label: '设备分组', label: '设备分组',
component: 'ApiSelect', component: 'ApiSelect',
componentProps: { componentProps: {
api: () => getSimpleDeviceGroupList(), api: getSimpleDeviceGroupList,
labelField: 'name', labelField: 'name',
valueField: 'id', valueField: 'id',
mode: 'multiple', mode: 'multiple',
@@ -199,7 +199,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
label: '产品', label: '产品',
component: 'ApiSelect', component: 'ApiSelect',
componentProps: { componentProps: {
api: () => getSimpleProductList(), api: getSimpleProductList,
labelField: 'name', labelField: 'name',
valueField: 'id', valueField: 'id',
placeholder: '请选择产品', placeholder: '请选择产品',
@@ -249,7 +249,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
label: '设备分组', label: '设备分组',
component: 'ApiSelect', component: 'ApiSelect',
componentProps: { componentProps: {
api: () => getSimpleDeviceGroupList(), api: getSimpleDeviceGroupList,
labelField: 'name', labelField: 'name',
valueField: 'id', valueField: 'id',
placeholder: '请选择设备分组', placeholder: '请选择设备分组',

View File

@@ -34,7 +34,7 @@ export function useFormSchema(): VbenFormSchema[] {
label: '父级分组', label: '父级分组',
component: 'ApiTreeSelect', component: 'ApiTreeSelect',
componentProps: { componentProps: {
api: () => getSimpleDeviceGroupList(), api: getSimpleDeviceGroupList,
labelField: 'name', labelField: 'name',
valueField: 'id', valueField: 'id',
placeholder: '请选择父级分组', placeholder: '请选择父级分组',

View File

@@ -29,7 +29,7 @@ export function useFormSchema(): VbenFormSchema[] {
label: '所属产品', label: '所属产品',
component: 'ApiSelect', component: 'ApiSelect',
componentProps: { componentProps: {
api: () => getSimpleProductList(), api: getSimpleProductList,
labelField: 'name', labelField: 'name',
valueField: 'id', valueField: 'id',
placeholder: '请选择产品', placeholder: '请选择产品',
@@ -85,7 +85,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
label: '产品', label: '产品',
component: 'ApiSelect', component: 'ApiSelect',
componentProps: { componentProps: {
api: () => getSimpleProductList(), api: getSimpleProductList,
labelField: 'name', labelField: 'name',
valueField: 'id', valueField: 'id',
placeholder: '请选择产品', placeholder: '请选择产品',
@@ -96,7 +96,10 @@ export function useGridFormSchema(): VbenFormSchema[] {
fieldName: 'createTime', fieldName: 'createTime',
label: '创建时间', label: '创建时间',
component: 'RangePicker', component: 'RangePicker',
componentProps: getRangePickerDefaultProps(), componentProps: {
...getRangePickerDefaultProps(),
allowClear: true,
},
}, },
]; ];
} }

View File

@@ -29,7 +29,7 @@ export function useFormSchema(): VbenFormSchema[] {
label: '所属产品', label: '所属产品',
component: 'ApiSelect', component: 'ApiSelect',
componentProps: { componentProps: {
api: () => getSimpleProductList(), api: getSimpleProductList,
labelField: 'name', labelField: 'name',
valueField: 'id', valueField: 'id',
placeholder: '请选择产品', placeholder: '请选择产品',
@@ -86,7 +86,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
label: '产品', label: '产品',
component: 'ApiSelect', component: 'ApiSelect',
componentProps: { componentProps: {
api: () => getSimpleProductList(), api: getSimpleProductList,
labelField: 'name', labelField: 'name',
valueField: 'id', valueField: 'id',
placeholder: '请选择产品', placeholder: '请选择产品',
@@ -97,7 +97,10 @@ export function useGridFormSchema(): VbenFormSchema[] {
fieldName: 'createTime', fieldName: 'createTime',
label: '创建时间', label: '创建时间',
component: 'RangePicker', component: 'RangePicker',
componentProps: getRangePickerDefaultProps(), componentProps: {
...getRangePickerDefaultProps(),
allowClear: true,
},
}, },
]; ];
} }

View File

@@ -2,9 +2,10 @@
import type { VxeTableGridOptions } from '#/adapter/vxe-table'; import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { IoTOtaFirmwareApi } from '#/api/iot/ota/firmware'; import type { IoTOtaFirmwareApi } from '#/api/iot/ota/firmware';
import { useRouter } from 'vue-router';
import { Page, useVbenModal } from '@vben/common-ui'; import { Page, useVbenModal } from '@vben/common-ui';
import { IconifyIcon } from '@vben/icons'; import { IconifyIcon } from '@vben/icons';
import { useRouter } from 'vue-router';
import { message } from 'ant-design-vue'; import { message } from 'ant-design-vue';
@@ -39,7 +40,6 @@ function handleEdit(row: IoTOtaFirmwareApi.Firmware) {
formModalApi.setData({ type: 'update', id: row.id }).open(); formModalApi.setData({ type: 'update', id: row.id }).open();
} }
/** 删除固件 */ /** 删除固件 */
async function handleDelete(row: IoTOtaFirmwareApi.Firmware) { async function handleDelete(row: IoTOtaFirmwareApi.Firmware) {
const hideLoading = message.loading({ const hideLoading = message.loading({
@@ -117,19 +117,25 @@ const [Grid, gridApi] = useVbenVxeGrid({
<!-- 固件文件列 --> <!-- 固件文件列 -->
<template #fileUrl="{ row }"> <template #fileUrl="{ row }">
<div v-if="row.fileUrl" class="inline-flex items-center gap-1.5 align-middle leading-none"> <div
<IconifyIcon icon="ant-design:download-outlined" class="shrink-0 text-base align-middle text-primary" /> v-if="row.fileUrl"
class="inline-flex items-center gap-1.5 align-middle leading-none"
>
<IconifyIcon
icon="ant-design:download-outlined"
class="text-primary shrink-0 align-middle text-base"
/>
<a <a
:href="row.fileUrl" :href="row.fileUrl"
target="_blank" target="_blank"
download download
class="text-primary cursor-pointer hover:underline align-middle" class="text-primary cursor-pointer align-middle hover:underline"
> >
下载固件 下载固件
</a> </a>
</div> </div>
<span v-else class="text-gray-400">无文件</span> <span v-else class="text-gray-400">无文件</span>
</template> </template>
<!-- 操作列 --> <!-- 操作列 -->
<template #actions="{ row }"> <template #actions="{ row }">

View File

@@ -34,7 +34,7 @@ export function useFormSchema(): VbenFormSchema[] {
label: '父级分类', label: '父级分类',
component: 'ApiTreeSelect', component: 'ApiTreeSelect',
componentProps: { componentProps: {
api: () => getSimpleProductCategoryList(), api: getSimpleProductCategoryList,
labelField: 'name', labelField: 'name',
valueField: 'id', valueField: 'id',
placeholder: '请选择父级分类', placeholder: '请选择父级分类',

View File

@@ -93,7 +93,7 @@ export function useFormSchema(formApi?: any): VbenFormSchema[] {
label: '产品分类', label: '产品分类',
component: 'ApiSelect', component: 'ApiSelect',
componentProps: { componentProps: {
api: () => getSimpleProductCategoryList(), api: getSimpleProductCategoryList,
labelField: 'name', labelField: 'name',
valueField: 'id', valueField: 'id',
placeholder: '请选择产品分类', placeholder: '请选择产品分类',
@@ -246,7 +246,7 @@ export function useBasicFormSchema(formApi?: any): VbenFormSchema[] {
label: '产品分类', label: '产品分类',
component: 'ApiSelect', component: 'ApiSelect',
componentProps: { componentProps: {
api: () => getSimpleProductCategoryList(), api: getSimpleProductCategoryList,
labelField: 'name', labelField: 'name',
valueField: 'id', valueField: 'id',
placeholder: '请选择产品分类', placeholder: '请选择产品分类',

View File

@@ -24,7 +24,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
label: '产品', label: '产品',
component: 'ApiSelect', component: 'ApiSelect',
componentProps: { componentProps: {
api: () => getSimpleProductList(), api: getSimpleProductList,
labelField: 'name', labelField: 'name',
valueField: 'id', valueField: 'id',
placeholder: '请选择产品', placeholder: '请选择产品',
@@ -45,7 +45,10 @@ export function useGridFormSchema(): VbenFormSchema[] {
fieldName: 'createTime', fieldName: 'createTime',
label: '创建时间', label: '创建时间',
component: 'RangePicker', component: 'RangePicker',
componentProps: getRangePickerDefaultProps(), componentProps: {
...getRangePickerDefaultProps(),
allowClear: true,
},
}, },
]; ];
} }

View File

@@ -32,7 +32,10 @@ export function useGridFormSchema(): VbenFormSchema[] {
fieldName: 'createTime', fieldName: 'createTime',
label: '创建时间', label: '创建时间',
component: 'RangePicker', component: 'RangePicker',
componentProps: getRangePickerDefaultProps(), componentProps: {
...getRangePickerDefaultProps(),
allowClear: true,
},
}, },
]; ];
} }

View File

@@ -42,7 +42,10 @@ export function useGridFormSchema(): VbenFormSchema[] {
fieldName: 'createTime', fieldName: 'createTime',
label: '创建时间', label: '创建时间',
component: 'RangePicker', component: 'RangePicker',
componentProps: getRangePickerDefaultProps(), componentProps: {
...getRangePickerDefaultProps(),
allowClear: true,
},
}, },
]; ];
} }

View File

@@ -77,7 +77,10 @@ export function useGridFormSchema(): VbenFormSchema[] {
fieldName: 'createTime', fieldName: 'createTime',
label: '创建时间', label: '创建时间',
component: 'RangePicker', component: 'RangePicker',
componentProps: getRangePickerDefaultProps(), componentProps: {
...getRangePickerDefaultProps(),
allowClear: true,
},
}, },
]; ];
} }

View File

@@ -101,7 +101,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
{ {
fieldName: 'replyStatus', fieldName: 'replyStatus',
label: '回复状态', label: '回复状态',
component: 'Select', component: 'RadioGroup',
componentProps: { componentProps: {
options: [ options: [
{ label: '已回复', value: true }, { label: '已回复', value: true },

View File

@@ -283,7 +283,7 @@ function openPropertyAddForm() {
} }
/** 调用 SkuList generateTableData 方法*/ /** 调用 SkuList generateTableData 方法*/
function generateSkus(propertyList: any[]) { function generateSkus(propertyList: PropertyAndValues[]) {
skuListRef.value.generateTableData(propertyList); skuListRef.value.generateTableData(propertyList);
} }

View File

@@ -6,7 +6,9 @@ import type { MallPropertyApi } from '#/api/mall/product/property';
import { computed, ref, watch } from 'vue'; import { computed, ref, watch } from 'vue';
import { Button, Col, Divider, message, Select, Tag } from 'ant-design-vue'; import { IconifyIcon } from '@vben/icons';
import { Col, Divider, message, Select, Tag } from 'ant-design-vue';
import { import {
createPropertyValue, createPropertyValue,
@@ -80,13 +82,19 @@ watch(
); );
/** 删除属性值 */ /** 删除属性值 */
function handleCloseValue(index: number, valueIndex: number) { function handleCloseValue(index: number, value: PropertyAndValues) {
attributeList.value?.[index]?.values?.splice(valueIndex, 1); if (attributeList.value[index]) {
attributeList.value[index].values = attributeList.value?.[
index
]?.values?.filter((item) => item.id !== value.id);
}
} }
/** 删除属性 */ /** 删除属性 */
function handleCloseProperty(index: number) { function handleCloseProperty(item: PropertyAndValues) {
attributeList.value?.splice(index, 1); attributeList.value = attributeList.value.filter(
(attribute) => attribute.id !== item.id,
);
emit('success', attributeList.value); emit('success', attributeList.value);
} }
@@ -158,27 +166,28 @@ async function getAttributeOptions(propertyId: number) {
</script> </script>
<template> <template>
<Col v-for="(item, index) in attributeList" :key="index"> <Col v-for="(attribute, index) in attributeList" :key="index">
<Divider class="my-4" />
<!-- TODO @puhui9991间隙可以看看2)vue3 + element-plus 添加属性这个按钮是和属性名在一排感觉更好看点 --> <!-- TODO @puhui9991间隙可以看看2)vue3 + element-plus 添加属性这个按钮是和属性名在一排感觉更好看点 -->
<div> <div class="mt-1">
<span class="mx-1">属性名</span> <span class="mx-1">属性名</span>
<Tag <Tag
:closable="!isDetail" :closable="!isDetail"
class="mx-1" class="mx-1"
color="success" color="success"
@close="handleCloseProperty(index)" @close="handleCloseProperty(attribute)"
> >
{{ item.name }} {{ attribute.name }}
</Tag> </Tag>
</div> </div>
<div> <div class="mt-2">
<span class="mx-1">属性值</span> <span class="mx-1">属性值</span>
<Tag <Tag
v-for="(value, valueIndex) in item.values" v-for="(value, valueIndex) in attribute.values"
:key="value.id" :key="valueIndex"
:closable="!isDetail" :closable="!isDetail"
class="mx-1" class="mx-1"
@close="handleCloseValue(index, valueIndex)" @close="handleCloseValue(index, value)"
> >
<!-- TODO @puhui999这里貌似爆红idea --> <!-- TODO @puhui999这里貌似爆红idea -->
{{ value.name }} {{ value.name }}
@@ -194,9 +203,9 @@ async function getAttributeOptions(propertyId: number) {
:filter-option="true" :filter-option="true"
size="small" size="small"
style="width: 100px" style="width: 100px"
@blur="handleInputConfirm(index, item.id)" @blur="handleInputConfirm(index, attribute.id)"
@change="handleInputConfirm(index, item.id)" @change="handleInputConfirm(index, attribute.id)"
@keyup.enter="handleInputConfirm(index, item.id)" @keyup.enter="handleInputConfirm(index, attribute.id)"
> >
<Select.Option <Select.Option
v-for="item2 in attributeOptions" v-for="item2 in attributeOptions"
@@ -206,15 +215,16 @@ async function getAttributeOptions(propertyId: number) {
{{ item2.name }} {{ item2.name }}
</Select.Option> </Select.Option>
</Select> </Select>
<Button <Tag
v-show="!inputVisible(index)" v-show="!inputVisible(index)"
class="button-new-tag ml-1"
size="small"
@click="showInput(index)" @click="showInput(index)"
class="mx-1 border-dashed bg-gray-100"
> >
+ 添加 <div class="flex items-center">
</Button> <IconifyIcon class="mr-2" icon="lucide:plus" />
添加
</div>
</Tag>
</div> </div>
<Divider class="my-10px" />
</Col> </Col>
</template> </template>

View File

@@ -64,7 +64,6 @@ const formSchema: VbenFormSchema[] = [
filterOption: true, filterOption: true,
placeholder: '请选择属性名称。如果不存在,可手动输入选择', placeholder: '请选择属性名称。如果不存在,可手动输入选择',
mode: 'tags', mode: 'tags',
maxTagCount: 1,
allowClear: true, allowClear: true,
}, },
rules: 'required', rules: 'required',
@@ -77,7 +76,7 @@ const [Form, formApi] = useVbenForm({
class: 'w-full', class: 'w-full',
}, },
formItemClass: 'col-span-2', formItemClass: 'col-span-2',
labelWidth: 120, labelWidth: 80,
}, },
layout: 'horizontal', layout: 'horizontal',
schema: formSchema, schema: formSchema,
@@ -91,8 +90,11 @@ const [Modal, modalApi] = useVbenModal({
if (!valid) { if (!valid) {
return; return;
} }
modalApi.lock();
const values = await formApi.getValues(); const values = await formApi.getValues();
const name = Array.isArray(values.name) ? values.name[0] : values.name; // name 为数组,遍历数组,进行重复添加校验
const names = values.name;
for (const name of names) {
// 重复添加校验 // 重复添加校验
for (const attrItem of attributeList.value) { for (const attrItem of attributeList.value) {
if (attrItem.name === name) { if (attrItem.name === name) {
@@ -100,42 +102,35 @@ const [Modal, modalApi] = useVbenModal({
return; return;
} }
} }
}
// TODO @puhui999modalApi.lock(); 这种写法; for (const name of names) {
// 情况一:属性名已存在,则直接使用
const existProperty = attributeOptions.value.find( const existProperty = attributeOptions.value.find(
(item: MallPropertyApi.Property) => item.name === name, (item: MallPropertyApi.Property) => item.name === name,
); );
if (existProperty) { if (existProperty) {
// 情况一:如果属性已存在,则直接使用并结束
attributeList.value.push({ attributeList.value.push({
id: existProperty.id, id: existProperty.id,
name, name,
values: [], values: [],
}); });
// TODO @puhui999这里要不 if else这样 await modalApi.close(); emit('success'); 可以复用另外感觉甚至可以情况二add 后,成为 existProperty可以进一步简化 } else {
await modalApi.close();
emit('success');
return;
}
// 情况二:如果是不存在的属性,则需要执行新增 // 情况二:如果是不存在的属性,则需要执行新增
try { const propertyId = await createProperty({ name });
const data = { name } as MallPropertyApi.Property;
const propertyId = await createProperty(data);
// 添加到属性列表
attributeList.value.push({ attributeList.value.push({
id: propertyId, id: propertyId,
name, name,
values: [], values: [],
}); });
}
}
message.success($t('ui.actionMessage.operationSuccess')); message.success($t('ui.actionMessage.operationSuccess'));
modalApi.unlock();
await modalApi.close(); await modalApi.close();
emit('success'); emit('success');
} catch (error) {
console.error('添加属性失败:', error);
}
}, },
async onOpenChange(isOpen: boolean) { async onOpenChange(isOpen: boolean) {
if (!isOpen) { if (!isOpen) {
return; return;

View File

@@ -143,7 +143,7 @@ export function useGridColumns(): VxeTableGridOptions['columns'] {
field: 'status', field: 'status',
minWidth: 150, minWidth: 150,
cellRender: { cellRender: {
name: 'CellDictTag', name: 'CellDict',
props: { props: {
dictType: DICT_TYPE.COMMON_STATUS, dictType: DICT_TYPE.COMMON_STATUS,
}, },
@@ -154,7 +154,7 @@ export function useGridColumns(): VxeTableGridOptions['columns'] {
field: 'position', field: 'position',
minWidth: 150, minWidth: 150,
cellRender: { cellRender: {
name: 'CellDictTag', name: 'CellDict',
props: { props: {
dictType: DICT_TYPE.PROMOTION_BANNER_POSITION, dictType: DICT_TYPE.PROMOTION_BANNER_POSITION,
}, },

View File

@@ -197,15 +197,9 @@ function selectSku(skus: MallSpuApi.Sku[]) {
selectedSkuIds.value = []; selectedSkuIds.value = [];
return; return;
} }
props.radio
// TODO @puhui999有 idea 告警 ? (selectedSkuIds.value = [skus[0]?.id!])
if (props.radio) { : (selectedSkuIds.value = skus.map((sku) => sku.id!));
// 单选模式
selectedSkuIds.value = [skus[0]?.id!];
} else {
// 多选模式
selectedSkuIds.value = skus.map((sku) => sku.id!);
}
} }
/** 展开行,加载 SKU 列表 */ /** 展开行,加载 SKU 列表 */
@@ -280,7 +274,10 @@ const [Modal, modalApi] = useVbenModal({
await gridApi.query(); await gridApi.query();
}, },
}); });
defineExpose({
open: modalApi.open,
close: modalApi.close,
});
/** 初始化分类数据 */ /** 初始化分类数据 */
onMounted(async () => { onMounted(async () => {
categoryList.value = await getCategoryList({}); categoryList.value = await getCategoryList({});

View File

@@ -110,6 +110,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
label: $t('ui.actionTitle.create', ['积分活动']), label: $t('ui.actionTitle.create', ['积分活动']),
type: 'primary', type: 'primary',
icon: ACTION_ICON.ADD, icon: ACTION_ICON.ADD,
auth: ['promotion:point-activity:create'],
onClick: handleCreate, onClick: handleCreate,
}, },
]" ]"
@@ -122,6 +123,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
label: $t('common.edit'), label: $t('common.edit'),
type: 'link', type: 'link',
icon: ACTION_ICON.EDIT, icon: ACTION_ICON.EDIT,
auth: ['promotion:point-activity:update'],
onClick: handleEdit.bind(null, row), onClick: handleEdit.bind(null, row),
}, },
{ {
@@ -130,6 +132,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
danger: true, danger: true,
icon: ACTION_ICON.CLOSE, icon: ACTION_ICON.CLOSE,
ifShow: row.status === 0, ifShow: row.status === 0,
auth: ['promotion:point-activity:close'],
popConfirm: { popConfirm: {
title: '确认关闭该积分商城活动吗?', title: '确认关闭该积分商城活动吗?',
confirm: handleClose.bind(null, row), confirm: handleClose.bind(null, row),
@@ -141,6 +144,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
danger: true, danger: true,
icon: ACTION_ICON.DELETE, icon: ACTION_ICON.DELETE,
ifShow: row.status !== 0, ifShow: row.status !== 0,
auth: ['promotion:point-activity:delete'],
popConfirm: { popConfirm: {
title: $t('ui.actionMessage.deleteConfirm', [row.spuName]), title: $t('ui.actionMessage.deleteConfirm', [row.spuName]),
confirm: handleDelete.bind(null, row), confirm: handleDelete.bind(null, row),

View File

@@ -109,7 +109,7 @@ const gridColumns = computed<VxeGridProps['columns']>(() => {
field: 'marketPrice', field: 'marketPrice',
title: '原价', title: '原价',
minWidth: 100, minWidth: 100,
formatter: 'formatAmount', formatter: 'formatAmount2',
}, },
{ {
field: 'status', field: 'status',

View File

@@ -64,7 +64,7 @@ export function useGridColumns(): VxeTableGridOptions['columns'] {
minWidth: 120, minWidth: 120,
align: 'center', align: 'center',
cellRender: { cellRender: {
name: 'CellDictTag', name: 'CellDict',
props: { type: DICT_TYPE.PROMOTION_PRODUCT_SCOPE }, props: { type: DICT_TYPE.PROMOTION_PRODUCT_SCOPE },
}, },
}, },
@@ -88,7 +88,7 @@ export function useGridColumns(): VxeTableGridOptions['columns'] {
minWidth: 100, minWidth: 100,
align: 'center', align: 'center',
cellRender: { cellRender: {
name: 'CellDictTag', name: 'CellDict',
props: { type: DICT_TYPE.COMMON_STATUS }, props: { type: DICT_TYPE.COMMON_STATUS },
}, },
}, },

View File

@@ -53,7 +53,9 @@ async function handleClose(row: MallRewardActivityApi.RewardActivity) {
async function handleDelete(row: MallRewardActivityApi.RewardActivity) { async function handleDelete(row: MallRewardActivityApi.RewardActivity) {
await deleteRewardActivity(row.id!); await deleteRewardActivity(row.id!);
message.success($t('common.delSuccess')); message.success({
content: $t('ui.actionMessage.deleteSuccess', [row.id]),
});
handleRefresh(); handleRefresh();
} }

View File

@@ -146,7 +146,7 @@ export function useGridColumns(): VxeGridPropTypes.Columns {
width: 100, width: 100,
align: 'center', align: 'center',
cellRender: { cellRender: {
name: 'CellDictTag', name: 'CellDict',
props: { props: {
dictType: DICT_TYPE.TRADE_AFTER_SALE_STATUS, dictType: DICT_TYPE.TRADE_AFTER_SALE_STATUS,
}, },
@@ -158,7 +158,7 @@ export function useGridColumns(): VxeGridPropTypes.Columns {
width: 100, width: 100,
align: 'center', align: 'center',
cellRender: { cellRender: {
name: 'CellDictTag', name: 'CellDict',
props: { props: {
dictType: DICT_TYPE.TRADE_AFTER_SALE_WAY, dictType: DICT_TYPE.TRADE_AFTER_SALE_WAY,
}, },

View File

@@ -23,7 +23,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
{ {
fieldName: 'brokerageEnabled', fieldName: 'brokerageEnabled',
label: '推广资格', label: '推广资格',
component: 'Select', component: 'RadioGroup',
componentProps: { componentProps: {
placeholder: '请选择推广资格', placeholder: '请选择推广资格',
allowClear: true, allowClear: true,

View File

@@ -139,7 +139,7 @@ export function useGridColumns(): VxeTableGridOptions['columns'] {
field: 'status', field: 'status',
minWidth: 150, minWidth: 150,
cellRender: { cellRender: {
name: 'CellDictTag', name: 'CellDict',
props: { props: {
dictType: DICT_TYPE.COMMON_STATUS, dictType: DICT_TYPE.COMMON_STATUS,
}, },
@@ -150,7 +150,7 @@ export function useGridColumns(): VxeTableGridOptions['columns'] {
field: 'position', field: 'position',
minWidth: 150, minWidth: 150,
cellRender: { cellRender: {
name: 'CellDictTag', name: 'CellDict',
props: { props: {
dictType: DICT_TYPE.PROMOTION_BANNER_POSITION, dictType: DICT_TYPE.PROMOTION_BANNER_POSITION,
}, },

View File

@@ -146,7 +146,7 @@ export function useGridColumns(): VxeGridPropTypes.Columns {
width: 100, width: 100,
align: 'center', align: 'center',
cellRender: { cellRender: {
name: 'CellDictTag', name: 'CellDict',
props: { props: {
dictType: DICT_TYPE.TRADE_AFTER_SALE_STATUS, dictType: DICT_TYPE.TRADE_AFTER_SALE_STATUS,
}, },
@@ -158,7 +158,7 @@ export function useGridColumns(): VxeGridPropTypes.Columns {
width: 100, width: 100,
align: 'center', align: 'center',
cellRender: { cellRender: {
name: 'CellDictTag', name: 'CellDict',
props: { props: {
dictType: DICT_TYPE.TRADE_AFTER_SALE_WAY, dictType: DICT_TYPE.TRADE_AFTER_SALE_WAY,
}, },