Files
TakeoutSaaS.TenantUI/apps/web-antd/src/views/member/points-mall/composables/points-mall-page/helpers.ts

235 lines
7.8 KiB
TypeScript

import type {
ExportMemberPointMallRecordQuery,
MemberPointMallProductDto,
MemberPointMallRecordListQuery,
SaveMemberPointMallProductPayload,
SaveMemberPointMallRulePayload,
} from '#/api/member/points-mall';
import type {
PointMallProductEditorForm,
PointMallRecordFilterForm,
PointMallRuleForm,
} from '#/views/member/points-mall/types';
import {
createDefaultPointMallProductEditorForm,
createDefaultPointMallRuleForm,
} from '#/views/member/points-mall/types';
/** 数量格式化。 */
export function formatInteger(value: null | number | undefined) {
const num = Number(value ?? 0);
if (!Number.isFinite(num)) {
return '0';
}
return Math.round(num).toLocaleString('zh-CN');
}
/** 积分格式化。 */
export function formatPoints(value: null | number | undefined) {
return formatInteger(value);
}
/** 金额格式化。 */
export function formatCurrency(value: null | number | undefined) {
const amount = Number(value ?? 0);
if (Number.isNaN(amount)) {
return '¥0.00';
}
return `¥${amount.toFixed(2)}`;
}
/** 判断字符串是否为空。 */
export function isBlank(value: string | undefined) {
return !value || value.trim().length === 0;
}
/** 规则 DTO -> 表单。 */
export function mapRuleToForm(
rule: SaveMemberPointMallRulePayload,
): PointMallRuleForm {
return {
isConsumeRewardEnabled: Boolean(rule.isConsumeRewardEnabled),
consumeAmountPerStep: Number(rule.consumeAmountPerStep),
consumeRewardPointsPerStep: Number(rule.consumeRewardPointsPerStep),
isReviewRewardEnabled: Boolean(rule.isReviewRewardEnabled),
reviewRewardPoints: Number(rule.reviewRewardPoints),
isRegisterRewardEnabled: Boolean(rule.isRegisterRewardEnabled),
registerRewardPoints: Number(rule.registerRewardPoints),
isSigninRewardEnabled: Boolean(rule.isSigninRewardEnabled),
signinRewardPoints: Number(rule.signinRewardPoints),
expiryMode: rule.expiryMode,
};
}
/** 规则表单 -> 保存 DTO。 */
export function mapRuleFormToSavePayload(
form: PointMallRuleForm,
storeId: string,
): SaveMemberPointMallRulePayload {
return {
storeId,
isConsumeRewardEnabled: form.isConsumeRewardEnabled,
consumeAmountPerStep: Number(form.consumeAmountPerStep ?? 0),
consumeRewardPointsPerStep: Number(form.consumeRewardPointsPerStep ?? 0),
isReviewRewardEnabled: form.isReviewRewardEnabled,
reviewRewardPoints: Number(form.reviewRewardPoints ?? 0),
isRegisterRewardEnabled: form.isRegisterRewardEnabled,
registerRewardPoints: Number(form.registerRewardPoints ?? 0),
isSigninRewardEnabled: form.isSigninRewardEnabled,
signinRewardPoints: Number(form.signinRewardPoints ?? 0),
expiryMode: form.expiryMode,
};
}
/** 重置规则表单。 */
export function resetRuleForm(form: PointMallRuleForm) {
const defaults = createDefaultPointMallRuleForm();
form.isConsumeRewardEnabled = defaults.isConsumeRewardEnabled;
form.consumeAmountPerStep = defaults.consumeAmountPerStep;
form.consumeRewardPointsPerStep = defaults.consumeRewardPointsPerStep;
form.isReviewRewardEnabled = defaults.isReviewRewardEnabled;
form.reviewRewardPoints = defaults.reviewRewardPoints;
form.isRegisterRewardEnabled = defaults.isRegisterRewardEnabled;
form.registerRewardPoints = defaults.registerRewardPoints;
form.isSigninRewardEnabled = defaults.isSigninRewardEnabled;
form.signinRewardPoints = defaults.signinRewardPoints;
form.expiryMode = defaults.expiryMode;
}
/** 商品 DTO -> 编辑表单。 */
export function mapProductToEditorForm(
source: MemberPointMallProductDto,
): PointMallProductEditorForm {
return {
pointMallProductId: source.pointMallProductId,
redeemType: source.redeemType,
productId: source.productId ?? '',
productName: '',
couponTemplateId: source.couponTemplateId ?? '',
couponTemplateName: '',
physicalName: source.physicalName ?? '',
pickupMethod: source.pickupMethod ?? 'store_pickup',
name: source.name,
imageUrl: source.imageUrl ?? '',
exchangeType: source.exchangeType,
requiredPoints: source.requiredPoints,
cashAmount: source.exchangeType === 'mixed' ? source.cashAmount : null,
stockTotal: source.stockTotal,
perMemberLimit: source.perMemberLimit ?? null,
description: source.description ?? '',
notifyChannels: [...source.notifyChannels],
status: source.status,
};
}
/** 商品表单 -> 保存 DTO。 */
export function mapProductEditorFormToSavePayload(
form: PointMallProductEditorForm,
storeId: string,
): SaveMemberPointMallProductPayload {
return {
storeId,
pointMallProductId: form.pointMallProductId || undefined,
name: form.name.trim(),
imageUrl: form.imageUrl.trim() || undefined,
redeemType: form.redeemType,
productId: form.productId || undefined,
couponTemplateId: form.couponTemplateId || undefined,
physicalName: form.physicalName.trim() || undefined,
pickupMethod:
form.redeemType === 'physical' ? form.pickupMethod : undefined,
description: form.description.trim() || undefined,
exchangeType: form.exchangeType,
requiredPoints: Number(form.requiredPoints ?? 0),
cashAmount: Number(form.cashAmount ?? 0),
stockTotal: Number(form.stockTotal ?? 0),
perMemberLimit:
form.perMemberLimit && form.perMemberLimit > 0
? Number(form.perMemberLimit)
: undefined,
notifyChannels: [...form.notifyChannels],
status: form.status,
};
}
/** 重置商品编辑表单。 */
export function resetProductEditorForm(form: PointMallProductEditorForm) {
const defaults = createDefaultPointMallProductEditorForm();
form.pointMallProductId = defaults.pointMallProductId;
form.redeemType = defaults.redeemType;
form.productId = defaults.productId;
form.productName = defaults.productName;
form.couponTemplateId = defaults.couponTemplateId;
form.couponTemplateName = defaults.couponTemplateName;
form.physicalName = defaults.physicalName;
form.pickupMethod = defaults.pickupMethod;
form.name = defaults.name;
form.imageUrl = defaults.imageUrl;
form.exchangeType = defaults.exchangeType;
form.requiredPoints = defaults.requiredPoints;
form.cashAmount = defaults.cashAmount;
form.stockTotal = defaults.stockTotal;
form.perMemberLimit = defaults.perMemberLimit;
form.description = defaults.description;
form.notifyChannels = [...defaults.notifyChannels];
form.status = defaults.status;
}
/** 记录筛选项映射。 */
export function mapRecordFilterToQuery(
filterForm: PointMallRecordFilterForm,
): Pick<
ExportMemberPointMallRecordQuery & MemberPointMallRecordListQuery,
'endDate' | 'keyword' | 'redeemType' | 'startDate' | 'status'
> {
const query: Pick<
ExportMemberPointMallRecordQuery & MemberPointMallRecordListQuery,
'endDate' | 'keyword' | 'redeemType' | 'startDate' | 'status'
> = {};
if (filterForm.redeemType) {
query.redeemType = filterForm.redeemType;
}
if (filterForm.status) {
query.status = filterForm.status;
}
const keyword = filterForm.keyword.trim();
if (keyword) {
query.keyword = keyword;
}
if (filterForm.dateRange && filterForm.dateRange.length === 2) {
query.startDate = filterForm.dateRange[0].format('YYYY-MM-DD');
query.endDate = filterForm.dateRange[1].format('YYYY-MM-DD');
}
return query;
}
/** base64 下载。 */
export function downloadBase64File(
fileName: string,
fileContentBase64: string,
) {
const binary = atob(fileContentBase64);
const length = binary.length;
const bytes = new Uint8Array(length);
for (let index = 0; index < length; index++) {
bytes[index] = binary.codePointAt(index) ?? 0;
}
const blob = new Blob([bytes], { type: 'text/csv;charset=utf-8;' });
const url = URL.createObjectURL(blob);
const anchor = document.createElement('a');
anchor.href = url;
anchor.download = fileName;
document.body.append(anchor);
anchor.click();
anchor.remove();
URL.revokeObjectURL(url);
}