357 lines
9.5 KiB
TypeScript
357 lines
9.5 KiB
TypeScript
import type { Ref } from 'vue';
|
|
|
|
import type {
|
|
PointMallProductCardViewModel,
|
|
PointMallProductEditorForm,
|
|
} from '#/views/member/points-mall/types';
|
|
|
|
import { message } from 'ant-design-vue';
|
|
|
|
import { getMemberCouponPickerApi } from '#/api/member';
|
|
import {
|
|
getMemberPointMallProductDetailApi,
|
|
saveMemberPointMallProductApi,
|
|
} from '#/api/member/points-mall';
|
|
|
|
import {
|
|
mapProductEditorFormToSavePayload,
|
|
mapProductToEditorForm,
|
|
resetProductEditorForm,
|
|
} from './helpers';
|
|
|
|
interface CouponOption {
|
|
label: string;
|
|
value: string;
|
|
}
|
|
|
|
interface CreateDrawerActionsOptions {
|
|
canManage: Ref<boolean>;
|
|
couponOptions: Ref<CouponOption[]>;
|
|
drawerMode: Ref<'create' | 'edit'>;
|
|
form: PointMallProductEditorForm;
|
|
isDrawerLoading: Ref<boolean>;
|
|
isDrawerOpen: Ref<boolean>;
|
|
isDrawerSubmitting: Ref<boolean>;
|
|
loadProductList: () => Promise<void>;
|
|
openPicker: (currentProductId?: string) => Promise<void>;
|
|
selectedStoreId: Ref<string>;
|
|
}
|
|
|
|
export function createDrawerActions(options: CreateDrawerActionsOptions) {
|
|
async function loadCouponOptions(keyword?: string) {
|
|
if (!options.selectedStoreId.value) {
|
|
options.couponOptions.value = [];
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const rows = await getMemberCouponPickerApi({
|
|
storeId: options.selectedStoreId.value,
|
|
keyword: keyword?.trim() || undefined,
|
|
});
|
|
options.couponOptions.value = rows.map((item) => ({
|
|
label: item.displayText || item.name,
|
|
value: item.couponTemplateId,
|
|
}));
|
|
} catch (error) {
|
|
console.error(error);
|
|
options.couponOptions.value = [];
|
|
message.error('加载优惠券失败');
|
|
}
|
|
}
|
|
|
|
async function openCreateDrawer() {
|
|
if (!options.selectedStoreId.value) {
|
|
message.warning('请先选择门店');
|
|
return;
|
|
}
|
|
|
|
options.drawerMode.value = 'create';
|
|
resetProductEditorForm(options.form);
|
|
options.isDrawerLoading.value = false;
|
|
options.isDrawerOpen.value = true;
|
|
await loadCouponOptions();
|
|
}
|
|
|
|
async function openEditDrawer(item: PointMallProductCardViewModel) {
|
|
if (!options.selectedStoreId.value) {
|
|
message.warning('请先选择门店');
|
|
return;
|
|
}
|
|
|
|
options.drawerMode.value = 'edit';
|
|
options.isDrawerLoading.value = true;
|
|
options.isDrawerOpen.value = true;
|
|
|
|
try {
|
|
const detail = await getMemberPointMallProductDetailApi({
|
|
storeId: options.selectedStoreId.value,
|
|
pointMallProductId: item.pointMallProductId,
|
|
});
|
|
const mapped = mapProductToEditorForm(detail);
|
|
|
|
options.form.pointMallProductId = mapped.pointMallProductId;
|
|
options.form.redeemType = mapped.redeemType;
|
|
options.form.productId = mapped.productId;
|
|
options.form.productName = mapped.productName;
|
|
options.form.couponTemplateId = mapped.couponTemplateId;
|
|
options.form.couponTemplateName = mapped.couponTemplateName;
|
|
options.form.physicalName = mapped.physicalName;
|
|
options.form.pickupMethod = mapped.pickupMethod;
|
|
options.form.name = mapped.name;
|
|
options.form.imageUrl = mapped.imageUrl;
|
|
options.form.exchangeType = mapped.exchangeType;
|
|
options.form.requiredPoints = mapped.requiredPoints;
|
|
options.form.cashAmount = mapped.cashAmount;
|
|
options.form.stockTotal = mapped.stockTotal;
|
|
options.form.perMemberLimit = mapped.perMemberLimit;
|
|
options.form.description = mapped.description;
|
|
options.form.notifyChannels = [...mapped.notifyChannels];
|
|
options.form.status = mapped.status;
|
|
|
|
if (detail.redeemType === 'coupon') {
|
|
await loadCouponOptions();
|
|
const selected = options.couponOptions.value.find(
|
|
(row) => row.value === detail.couponTemplateId,
|
|
);
|
|
options.form.couponTemplateName = selected?.label ?? '';
|
|
}
|
|
} catch (error) {
|
|
console.error(error);
|
|
message.error('加载兑换商品详情失败');
|
|
options.isDrawerOpen.value = false;
|
|
} finally {
|
|
options.isDrawerLoading.value = false;
|
|
}
|
|
}
|
|
|
|
function setDrawerOpen(value: boolean) {
|
|
options.isDrawerOpen.value = value;
|
|
if (!value) {
|
|
options.isDrawerLoading.value = false;
|
|
options.isDrawerSubmitting.value = false;
|
|
}
|
|
}
|
|
|
|
function setFormName(value: string) {
|
|
options.form.name = value;
|
|
}
|
|
|
|
function setFormImageUrl(value: string) {
|
|
options.form.imageUrl = value;
|
|
}
|
|
|
|
function setFormRedeemType(value: PointMallProductEditorForm['redeemType']) {
|
|
options.form.redeemType = value;
|
|
|
|
if (value !== 'product') {
|
|
options.form.productId = '';
|
|
options.form.productName = '';
|
|
}
|
|
if (value !== 'coupon') {
|
|
options.form.couponTemplateId = '';
|
|
options.form.couponTemplateName = '';
|
|
}
|
|
if (value !== 'physical') {
|
|
options.form.physicalName = '';
|
|
options.form.pickupMethod = 'store_pickup';
|
|
}
|
|
|
|
if (value === 'physical') {
|
|
options.form.notifyChannels = ['in_app', 'sms'];
|
|
return;
|
|
}
|
|
|
|
if (!options.form.notifyChannels.includes('in_app')) {
|
|
options.form.notifyChannels = ['in_app'];
|
|
}
|
|
}
|
|
|
|
function setFormProduct(value: { id: string; name: string }) {
|
|
options.form.productId = value.id;
|
|
options.form.productName = value.name;
|
|
}
|
|
|
|
function setFormCouponTemplateId(value: string) {
|
|
options.form.couponTemplateId = value;
|
|
const selected = options.couponOptions.value.find(
|
|
(item) => item.value === value,
|
|
);
|
|
options.form.couponTemplateName = selected?.label ?? '';
|
|
}
|
|
|
|
function setFormPhysicalName(value: string) {
|
|
options.form.physicalName = value;
|
|
}
|
|
|
|
function setFormPickupMethod(
|
|
value: PointMallProductEditorForm['pickupMethod'],
|
|
) {
|
|
options.form.pickupMethod = value;
|
|
}
|
|
|
|
function setFormDescription(value: string) {
|
|
options.form.description = value;
|
|
}
|
|
|
|
function setFormExchangeType(
|
|
value: PointMallProductEditorForm['exchangeType'],
|
|
) {
|
|
options.form.exchangeType = value;
|
|
if (value === 'points') {
|
|
options.form.cashAmount = null;
|
|
}
|
|
}
|
|
|
|
function setFormRequiredPoints(value: null | number) {
|
|
options.form.requiredPoints = value;
|
|
}
|
|
|
|
function setFormCashAmount(value: null | number) {
|
|
options.form.cashAmount = value;
|
|
}
|
|
|
|
function setFormStockTotal(value: null | number) {
|
|
options.form.stockTotal = value;
|
|
}
|
|
|
|
function setFormPerMemberLimit(value: null | number) {
|
|
options.form.perMemberLimit = value;
|
|
}
|
|
|
|
function setFormStatus(value: PointMallProductEditorForm['status']) {
|
|
options.form.status = value;
|
|
}
|
|
|
|
function toggleNotifyChannel(value: 'in_app' | 'sms') {
|
|
if (options.form.notifyChannels.includes(value)) {
|
|
if (options.form.notifyChannels.length === 1) {
|
|
return;
|
|
}
|
|
options.form.notifyChannels = options.form.notifyChannels.filter(
|
|
(item) => item !== value,
|
|
);
|
|
return;
|
|
}
|
|
|
|
options.form.notifyChannels = [...options.form.notifyChannels, value];
|
|
}
|
|
|
|
async function openProductPicker() {
|
|
await options.openPicker(options.form.productId || undefined);
|
|
}
|
|
|
|
function validateForm() {
|
|
if (!options.form.name.trim()) {
|
|
message.warning('请填写展示名称');
|
|
return false;
|
|
}
|
|
|
|
if (!options.form.requiredPoints || options.form.requiredPoints <= 0) {
|
|
message.warning('所需积分必须大于 0');
|
|
return false;
|
|
}
|
|
|
|
if (options.form.stockTotal === null || options.form.stockTotal < 0) {
|
|
message.warning('库存数量不能小于 0');
|
|
return false;
|
|
}
|
|
|
|
if (options.form.redeemType === 'product' && !options.form.productId) {
|
|
message.warning('请选择关联商品');
|
|
return false;
|
|
}
|
|
|
|
if (
|
|
options.form.redeemType === 'coupon' &&
|
|
!options.form.couponTemplateId.trim()
|
|
) {
|
|
message.warning('请选择关联优惠券');
|
|
return false;
|
|
}
|
|
|
|
if (
|
|
options.form.redeemType === 'physical' &&
|
|
!options.form.physicalName.trim()
|
|
) {
|
|
message.warning('请填写实物名称');
|
|
return false;
|
|
}
|
|
|
|
if (
|
|
options.form.exchangeType === 'mixed' &&
|
|
(!options.form.cashAmount || options.form.cashAmount <= 0)
|
|
) {
|
|
message.warning('积分+现金模式下,现金部分必须大于 0');
|
|
return false;
|
|
}
|
|
|
|
if (options.form.notifyChannels.length === 0) {
|
|
message.warning('请至少选择一种通知方式');
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
async function submitDrawer() {
|
|
if (!options.canManage.value) {
|
|
return;
|
|
}
|
|
|
|
if (!options.selectedStoreId.value) {
|
|
message.warning('请先选择门店');
|
|
return;
|
|
}
|
|
|
|
if (!validateForm()) {
|
|
return;
|
|
}
|
|
|
|
options.isDrawerSubmitting.value = true;
|
|
try {
|
|
await saveMemberPointMallProductApi(
|
|
mapProductEditorFormToSavePayload(
|
|
options.form,
|
|
options.selectedStoreId.value,
|
|
),
|
|
);
|
|
|
|
message.success(
|
|
options.drawerMode.value === 'create' ? '添加成功' : '保存成功',
|
|
);
|
|
options.isDrawerOpen.value = false;
|
|
await options.loadProductList();
|
|
} catch (error) {
|
|
console.error(error);
|
|
message.error('保存失败');
|
|
} finally {
|
|
options.isDrawerSubmitting.value = false;
|
|
}
|
|
}
|
|
|
|
return {
|
|
loadCouponOptions,
|
|
openCreateDrawer,
|
|
openEditDrawer,
|
|
openProductPicker,
|
|
setDrawerOpen,
|
|
setFormCashAmount,
|
|
setFormCouponTemplateId,
|
|
setFormDescription,
|
|
setFormExchangeType,
|
|
setFormImageUrl,
|
|
setFormName,
|
|
setFormPerMemberLimit,
|
|
setFormPhysicalName,
|
|
setFormPickupMethod,
|
|
setFormProduct,
|
|
setFormRedeemType,
|
|
setFormRequiredPoints,
|
|
setFormStatus,
|
|
setFormStockTotal,
|
|
submitDrawer,
|
|
toggleNotifyChannel,
|
|
};
|
|
}
|