feat(member): implement points mall module pages
This commit is contained in:
@@ -0,0 +1,234 @@
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user