Files
TakeoutSaaS.TenantUI/apps/web-antd/src/views/member/points-mall/index.vue

310 lines
9.4 KiB
Vue

<script setup lang="ts">
import { Page } from '@vben/common-ui';
import { Empty, Select, Spin } from 'ant-design-vue';
import PointsMallProductCard from './components/PointsMallProductCard.vue';
import PointsMallProductEditorDrawer from './components/PointsMallProductEditorDrawer.vue';
import PointsMallProductPickerModal from './components/PointsMallProductPickerModal.vue';
import PointsMallProductToolbar from './components/PointsMallProductToolbar.vue';
import PointsMallRecordDetailDrawer from './components/PointsMallRecordDetailDrawer.vue';
import PointsMallRecordStatsCards from './components/PointsMallRecordStatsCards.vue';
import PointsMallRecordTable from './components/PointsMallRecordTable.vue';
import PointsMallRecordToolbar from './components/PointsMallRecordToolbar.vue';
import PointsMallRulePanel from './components/PointsMallRulePanel.vue';
import PointsMallRuleStatsCards from './components/PointsMallRuleStatsCards.vue';
import PointsMallVerifyDrawer from './components/PointsMallVerifyDrawer.vue';
import { useMemberPointsMallPage } from './composables/useMemberPointsMallPage';
const {
activeTab,
applyProductFilters,
applyRecordFilters,
canManage,
canView,
couponOptions,
detailRecord,
drawerSubmitText,
drawerTitle,
exportRecords,
hasStore,
handleRecordPageChange,
isDetailLoading,
isDetailOpen,
isDrawerLoading,
isDrawerOpen,
isDrawerSubmitting,
isExporting,
isPickerLoading,
isPickerOpen,
isProductLoading,
isRecordLoading,
isRuleLoading,
isRuleSubmitting,
isStoreLoading,
isVerifyLoading,
isVerifyOpen,
isVerifySubmitting,
openCreateProduct,
openDetailDrawer,
openEditProduct,
openProductPickerDrawer,
openVerifyDrawer,
pickerKeyword,
pickerRows,
pickerSelectedId,
productFilterForm,
productForm,
productRows,
recordFilterForm,
recordPager,
recordStats,
removeProduct,
resetProductFilters,
resetRecordFilters,
ruleForm,
ruleStats,
saveRule,
selectedStoreId,
setActiveTab,
setDetailOpen,
setDrawerOpen,
setFormCashAmount,
setFormCouponTemplateId,
setFormDescription,
setFormExchangeType,
setFormImageUrl,
setFormName,
setFormPerMemberLimit,
setFormPhysicalName,
setFormPickupMethod,
setFormRedeemType,
setFormRequiredPoints,
setFormStatus,
setFormStockTotal,
setPickedProductId,
setPickerKeyword,
setPickerOpen,
setProductKeyword,
setProductStatusFilter,
setRecordKeyword,
setRecordRedeemType,
setRecordStatus,
setRuleConsumeAmountPerStep,
setRuleConsumeRewardEnabled,
setRuleConsumeRewardPointsPerStep,
setRuleExpiryMode,
setRuleRegisterRewardEnabled,
setRuleRegisterRewardPoints,
setRuleReviewRewardEnabled,
setRuleReviewRewardPoints,
setRuleSigninRewardEnabled,
setRuleSigninRewardPoints,
setSelectedStoreId,
setVerifyMethod,
setVerifyOpen,
setVerifyRemark,
searchCouponOptions,
searchPickerProducts,
storeOptions,
submitDrawer,
submitProductPicker,
submitVerify,
tabOptions,
toggleNotifyChannel,
toggleStatus,
verifyForm,
} = useMemberPointsMallPage();
</script>
<template>
<Page title="积分商城" content-class="page-member-points-mall">
<div class="mpm-page">
<div class="mpm-toolbar mpm-toolbar-top">
<Select
class="mpm-store-select"
:value="selectedStoreId"
:options="storeOptions"
:loading="isStoreLoading"
placeholder="请选择门店"
@update:value="(value) => setSelectedStoreId(String(value ?? ''))"
/>
<div class="mpm-segments">
<button
v-for="item in tabOptions"
:key="item.value"
type="button"
class="mpm-segment-item"
:class="{ active: activeTab === item.value }"
@click="setActiveTab(item.value)"
>
{{ item.label }}
</button>
</div>
<span v-if="canView && !canManage" class="mpm-readonly-tip">
当前为只读权限
</span>
</div>
<Empty v-if="!canView" description="暂无积分商城页面访问权限" />
<div v-else-if="!hasStore" class="mpm-empty">
<Empty description="暂无门店,请先创建门店" />
</div>
<template v-else>
<section v-show="activeTab === 'rules'" class="mpm-tab-panel">
<Spin :spinning="isRuleLoading">
<PointsMallRuleStatsCards :stats="ruleStats" />
<PointsMallRulePanel
:form="ruleForm"
:can-manage="canManage"
:loading="isRuleLoading"
:submitting="isRuleSubmitting"
@set-consume-reward-enabled="setRuleConsumeRewardEnabled"
@set-consume-amount-per-step="setRuleConsumeAmountPerStep"
@set-consume-reward-points-per-step="
setRuleConsumeRewardPointsPerStep
"
@set-review-reward-enabled="setRuleReviewRewardEnabled"
@set-review-reward-points="setRuleReviewRewardPoints"
@set-register-reward-enabled="setRuleRegisterRewardEnabled"
@set-register-reward-points="setRuleRegisterRewardPoints"
@set-signin-reward-enabled="setRuleSigninRewardEnabled"
@set-signin-reward-points="setRuleSigninRewardPoints"
@set-expiry-mode="setRuleExpiryMode"
@save="saveRule"
/>
</Spin>
</section>
<section v-show="activeTab === 'products'" class="mpm-tab-panel">
<PointsMallProductToolbar
:filters="productFilterForm"
:can-manage="canManage"
:loading="isProductLoading"
@set-status="setProductStatusFilter"
@set-keyword="setProductKeyword"
@search="applyProductFilters"
@reset="resetProductFilters"
@create="openCreateProduct"
/>
<Spin :spinning="isProductLoading">
<div v-if="productRows.length > 0" class="mpm-product-grid">
<PointsMallProductCard
v-for="item in productRows"
:key="item.pointMallProductId"
:item="item"
:can-manage="canManage"
@edit="openEditProduct"
@toggle-status="toggleStatus"
@remove="removeProduct"
/>
</div>
<div v-else class="mpm-empty">
<Empty description="暂无兑换商品" />
</div>
</Spin>
</section>
<section v-show="activeTab === 'records'" class="mpm-tab-panel">
<PointsMallRecordToolbar
:filters="recordFilterForm"
:can-manage="canManage"
:loading="isRecordLoading"
:exporting="isExporting"
@set-redeem-type="setRecordRedeemType"
@set-status="setRecordStatus"
@set-keyword="setRecordKeyword"
@search="applyRecordFilters"
@reset="resetRecordFilters"
@export="exportRecords"
/>
<PointsMallRecordStatsCards :stats="recordStats" />
<div class="mpm-table-panel">
<PointsMallRecordTable
:can-manage="canManage"
:loading="isRecordLoading"
:pager="recordPager"
@page-change="handleRecordPageChange"
@verify="openVerifyDrawer"
@detail="openDetailDrawer"
/>
</div>
</section>
</template>
</div>
<PointsMallProductEditorDrawer
:open="isDrawerOpen"
:title="drawerTitle"
:submit-text="drawerSubmitText"
:submitting="isDrawerSubmitting"
:loading="isDrawerLoading"
:can-manage="canManage"
:form="productForm"
:coupon-options="couponOptions"
@close="setDrawerOpen(false)"
@set-name="setFormName"
@set-image-url="setFormImageUrl"
@set-redeem-type="setFormRedeemType"
@set-coupon-template-id="setFormCouponTemplateId"
@set-physical-name="setFormPhysicalName"
@set-pickup-method="setFormPickupMethod"
@set-description="setFormDescription"
@set-exchange-type="setFormExchangeType"
@set-required-points="setFormRequiredPoints"
@set-cash-amount="setFormCashAmount"
@set-stock-total="setFormStockTotal"
@set-per-member-limit="setFormPerMemberLimit"
@set-status="setFormStatus"
@toggle-notify-channel="toggleNotifyChannel"
@submit="submitDrawer"
@open-product-picker="openProductPickerDrawer"
@search-coupon="searchCouponOptions"
/>
<PointsMallProductPickerModal
:open="isPickerOpen"
:loading="isPickerLoading"
:keyword="pickerKeyword"
:rows="pickerRows"
:selected-id="pickerSelectedId"
@close="setPickerOpen(false)"
@set-keyword="setPickerKeyword"
@search="searchPickerProducts"
@select="setPickedProductId"
@submit="submitProductPicker"
/>
<PointsMallVerifyDrawer
:open="isVerifyOpen"
:loading="isVerifyLoading"
:submitting="isVerifySubmitting"
:can-manage="canManage"
:record="detailRecord"
:form="verifyForm"
@close="setVerifyOpen(false)"
@set-verify-method="setVerifyMethod"
@set-verify-remark="setVerifyRemark"
@submit="submitVerify"
/>
<PointsMallRecordDetailDrawer
:open="isDetailOpen"
:loading="isDetailLoading"
:record="detailRecord"
@close="setDetailOpen(false)"
/>
</Page>
</template>
<style lang="less">
@import './styles/index.less';
</style>