|
@@ -0,0 +1,492 @@
|
|
|
|
|
+<script setup lang="tsx">
|
|
|
|
|
+import { ref } from 'vue';
|
|
|
|
|
+import { NButton, NTag } from 'naive-ui';
|
|
|
|
|
+import {
|
|
|
|
|
+ delActivity,
|
|
|
|
|
+ fetchAddActivity,
|
|
|
|
|
+ fetchEditActivity,
|
|
|
|
|
+ fetchGetActivityList,
|
|
|
|
|
+ fetchReceiveRecord,
|
|
|
|
|
+ fetchReceiveRecordCount
|
|
|
|
|
+} from '@/service/api/jy-manage/activity';
|
|
|
|
|
+import { useModalFrom } from '@/components/zt/ModalForm/hooks/useModalForm';
|
|
|
|
|
+import { useTable } from '@/components/zt/Table/hooks/useTable';
|
|
|
|
|
+import { useModal } from '@/components/zt/Modal/hooks/useModal';
|
|
|
|
|
+const couponId = ref();
|
|
|
|
|
+const countObj = ref({
|
|
|
|
|
+ provideNumber: '',
|
|
|
|
|
+ unclaimedNumber: 0,
|
|
|
|
|
+ receiveUnusedNumber: 0,
|
|
|
|
|
+ receiveUsedNumber: '',
|
|
|
|
|
+ receiveFreezeNumber: '',
|
|
|
|
|
+ receiveFailureNumber: ''
|
|
|
|
|
+});
|
|
|
|
|
+const [registerModalTable, { refresh }] = useTable({
|
|
|
|
|
+ searchFormConfig: {
|
|
|
|
|
+ schemas: [
|
|
|
|
|
+ {
|
|
|
|
|
+ field: 'activityName',
|
|
|
|
|
+ component: 'NInput',
|
|
|
|
|
+ label: '活动名称'
|
|
|
|
|
+ }
|
|
|
|
|
+ ],
|
|
|
|
|
+ inline: false,
|
|
|
|
|
+ size: 'small',
|
|
|
|
|
+ labelPlacement: 'left',
|
|
|
|
|
+ isFull: false
|
|
|
|
|
+ },
|
|
|
|
|
+ tableConfig: {
|
|
|
|
|
+ keyField: 'id',
|
|
|
|
|
+ title: '活动列表',
|
|
|
|
|
+ minHeight: 400
|
|
|
|
|
+ }
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+const [registerModal, { openModal }] = useModal({
|
|
|
|
|
+ title: '查看领取情况',
|
|
|
|
|
+ height: 800,
|
|
|
|
|
+ showFooter: false,
|
|
|
|
|
+ width: 1200
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+const [registerClaimModalTable, { refresh: refreshModal }] = useTable({
|
|
|
|
|
+ searchFormConfig: {
|
|
|
|
|
+ schemas: [
|
|
|
|
|
+ // {
|
|
|
|
|
+ // field: 'activityId',
|
|
|
|
|
+ // component: 'NInput',
|
|
|
|
|
+ // label: '券ID'
|
|
|
|
|
+ // },
|
|
|
|
|
+ {
|
|
|
|
|
+ field: 'batchId',
|
|
|
|
|
+ component: 'NInput',
|
|
|
|
|
+ label: '批次号'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ field: 'useStatus',
|
|
|
|
|
+ component: 'NSelect',
|
|
|
|
|
+ label: '状态',
|
|
|
|
|
+ componentProps: {
|
|
|
|
|
+ options: [
|
|
|
|
|
+ {
|
|
|
|
|
+ label: '已使用',
|
|
|
|
|
+ value: 1
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: '可使用',
|
|
|
|
|
+ value: 2
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: '已过期',
|
|
|
|
|
+ value: 5
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: '未生效',
|
|
|
|
|
+ value: 7
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ field: 'memberMobile',
|
|
|
|
|
+ component: 'NInput',
|
|
|
|
|
+ label: '用户手机号'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ field: 'lockOrderId',
|
|
|
|
|
+ component: 'NInput',
|
|
|
|
|
+ label: '订单号'
|
|
|
|
|
+ }
|
|
|
|
|
+ ],
|
|
|
|
|
+ inline: false,
|
|
|
|
|
+ size: 'small',
|
|
|
|
|
+ labelPlacement: 'left',
|
|
|
|
|
+ isFull: false
|
|
|
|
|
+ },
|
|
|
|
|
+ tableConfig: {
|
|
|
|
|
+ keyField: 'id',
|
|
|
|
|
+ title: '',
|
|
|
|
|
+ showAddButton: false,
|
|
|
|
|
+ minHeight: 400,
|
|
|
|
|
+ showTableHeaderAction: true
|
|
|
|
|
+ }
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+const [
|
|
|
|
|
+ registerModalForm,
|
|
|
|
|
+ {
|
|
|
|
|
+ openModal: openModalForm,
|
|
|
|
|
+ setFieldsValue: setModalFormValue,
|
|
|
|
|
+ getFieldsValue: getModalFormValue,
|
|
|
|
|
+ closeModal: closeModalForm,
|
|
|
|
|
+ setSubLoading
|
|
|
|
|
+ }
|
|
|
|
|
+] = useModalFrom({
|
|
|
|
|
+ modalConfig: {
|
|
|
|
|
+ title: '一级分类',
|
|
|
|
|
+ isShowHeaderText: true
|
|
|
|
|
+ },
|
|
|
|
|
+ formConfig: {
|
|
|
|
|
+ schemas: [
|
|
|
|
|
+ {
|
|
|
|
|
+ field: 'id',
|
|
|
|
|
+ label: 'ID',
|
|
|
|
|
+ show: false,
|
|
|
|
|
+ component: 'NInput'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ field: 'activityId',
|
|
|
|
|
+ label: '活动ID',
|
|
|
|
|
+ component: 'NInput',
|
|
|
|
|
+ required: true,
|
|
|
|
|
+ componentProps: {
|
|
|
|
|
+ placeholder: '小桔提供,务必仔细核对,保持一致'
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ field: 'activityName',
|
|
|
|
|
+ component: 'NInput',
|
|
|
|
|
+ label: '活动名称',
|
|
|
|
|
+ required: true,
|
|
|
|
|
+ componentProps: {
|
|
|
|
|
+ maxlength: 20
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ field: 'promotionType',
|
|
|
|
|
+ component: 'NRadioGroup',
|
|
|
|
|
+ label: '类型',
|
|
|
|
|
+ required: true,
|
|
|
|
|
+ defaultValue: 1,
|
|
|
|
|
+ componentProps: {
|
|
|
|
|
+ options: [
|
|
|
|
|
+ {
|
|
|
|
|
+ label: '满减券',
|
|
|
|
|
+ value: 1
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ label: '立减券',
|
|
|
|
|
+ value: 2
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ field: 'amountMoney',
|
|
|
|
|
+ component: 'NInputNumber',
|
|
|
|
|
+ label: '门槛(元)',
|
|
|
|
|
+ required: true,
|
|
|
|
|
+ componentProps: {
|
|
|
|
|
+ min: 0,
|
|
|
|
|
+ max: 1000,
|
|
|
|
|
+ precision: 2
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ field: 'discountMoney',
|
|
|
|
|
+ component: 'NInputNumber',
|
|
|
|
|
+ label: '面额(元)',
|
|
|
|
|
+ rules: { validator: validateDiscountMoney, trigger: 'input' },
|
|
|
|
|
+ componentProps: {
|
|
|
|
|
+ min: 0,
|
|
|
|
|
+ max: 1000,
|
|
|
|
|
+ precision: 2
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ field: 'inventory',
|
|
|
|
|
+ component: 'NInputNumber',
|
|
|
|
|
+ label: '库存',
|
|
|
|
|
+ required: true,
|
|
|
|
|
+ componentProps: {
|
|
|
|
|
+ min: 0,
|
|
|
|
|
+ max: 100000
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ field: 'purchasePrice',
|
|
|
|
|
+ component: 'NInputNumber',
|
|
|
|
|
+ label: '含税采购价(元)',
|
|
|
|
|
+ rules: { validator: validatePrice, message: '小于等于面额', trigger: 'input' },
|
|
|
|
|
+ componentProps: {
|
|
|
|
|
+ min: 0
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ field: 'createTime',
|
|
|
|
|
+ label: '发放有效期',
|
|
|
|
|
+ component: 'NDatePicker',
|
|
|
|
|
+ required: true,
|
|
|
|
|
+ componentProps: {
|
|
|
|
|
+ type: 'datetimerange',
|
|
|
|
|
+ defaultTime: ['00:00:00', '23:59:59']
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ field: 'expirationDate',
|
|
|
|
|
+ component: 'NInputNumber',
|
|
|
|
|
+ label: '券使用有效期',
|
|
|
|
|
+ required: true,
|
|
|
|
|
+ componentProps: {
|
|
|
|
|
+ min: 0,
|
|
|
|
|
+ max: 100000
|
|
|
|
|
+ },
|
|
|
|
|
+ render: ({ model, field }) => {
|
|
|
|
|
+ return (
|
|
|
|
|
+ <div class="flex items-center">
|
|
|
|
|
+ 领取后 <n-input-number v-model:value={model[field]} min={0} max={100} clearable /> 天有效
|
|
|
|
|
+ </div>
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ ],
|
|
|
|
|
+ labelWidth: 120,
|
|
|
|
|
+ layout: 'horizontal',
|
|
|
|
|
+ gridProps: {
|
|
|
|
|
+ cols: '1',
|
|
|
|
|
+ itemResponsive: true
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+const tableColumns: NaiveUI.TableColumn<Api.goods.ShopCategory>[] = [
|
|
|
|
|
+ {
|
|
|
|
|
+ title: '活动ID',
|
|
|
|
|
+ align: 'center',
|
|
|
|
|
+ key: 'activityId'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ title: '活动名称',
|
|
|
|
|
+ align: 'center',
|
|
|
|
|
+ key: 'activityName'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ title: '类型',
|
|
|
|
|
+ align: 'center',
|
|
|
|
|
+ key: 'promotionType',
|
|
|
|
|
+ render: row => {
|
|
|
|
|
+ return row.promotionType === 1 ? '满减券' : '立减券';
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ title: '门槛(元)',
|
|
|
|
|
+ align: 'center',
|
|
|
|
|
+ key: 'amountMoney'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ title: '面额(元)',
|
|
|
|
|
+ align: 'center',
|
|
|
|
|
+ key: 'discountMoney'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ title: '库存',
|
|
|
|
|
+ align: 'center',
|
|
|
|
|
+ key: 'inventoryTotal'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ title: '含税采购价(元)',
|
|
|
|
|
+ align: 'center',
|
|
|
|
|
+ key: 'purchasePrice'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ title: '发放有效期',
|
|
|
|
|
+ align: 'center',
|
|
|
|
|
+ key: 'createTime',
|
|
|
|
|
+ render: row => {
|
|
|
|
|
+ return `${row.couponStartTime}~${row.couponEndTime}`;
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ title: '券使用有效期',
|
|
|
|
|
+ align: 'center',
|
|
|
|
|
+ key: 'expirationDate'
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ {
|
|
|
|
|
+ title: '操作',
|
|
|
|
|
+ key: 'op',
|
|
|
|
|
+ fixed: 'right',
|
|
|
|
|
+ align: 'center',
|
|
|
|
|
+ width: 230,
|
|
|
|
|
+ render: row => (
|
|
|
|
|
+ <div class="flex-center gap-8px">
|
|
|
|
|
+ {
|
|
|
|
|
+ <NButton type="primary" size="small" ghost onClick={() => handleRecord(row.id)}>
|
|
|
|
|
+ 查看领取情况
|
|
|
|
|
+ </NButton>
|
|
|
|
|
+ }
|
|
|
|
|
+ {
|
|
|
|
|
+ <NButton type="primary" size="small" ghost onClick={() => edit(row)}>
|
|
|
|
|
+ 编辑
|
|
|
|
|
+ </NButton>
|
|
|
|
|
+ }
|
|
|
|
|
+ <NButton type="primary" size="small" ghost onClick={() => del(row)}>
|
|
|
|
|
+ 删除
|
|
|
|
|
+ </NButton>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+];
|
|
|
|
|
+
|
|
|
|
|
+const ModalColumns: NaiveUI.TableColumn<Api.government.PointsFailureRecordVO>[] = [
|
|
|
|
|
+ {
|
|
|
|
|
+ key: 'couponId',
|
|
|
|
|
+ title: '券ID',
|
|
|
|
|
+ align: 'center'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ key: 'batchId',
|
|
|
|
|
+ title: '批次号',
|
|
|
|
|
+ align: 'center'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ key: 'expirationTime',
|
|
|
|
|
+ title: '使用有效期至',
|
|
|
|
|
+ align: 'center'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ key: 'memberMobile',
|
|
|
|
|
+ title: '用户手机号',
|
|
|
|
|
+ align: 'center'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ key: 'userName',
|
|
|
|
|
+ title: '状态',
|
|
|
|
|
+ align: 'center',
|
|
|
|
|
+ render: row => {
|
|
|
|
|
+ const statuList = {
|
|
|
|
|
+ '1': '已使用',
|
|
|
|
|
+ '2': '可使用',
|
|
|
|
|
+ '5': '已过期',
|
|
|
|
|
+ '7': '未生效'
|
|
|
|
|
+ };
|
|
|
|
|
+ return <NTag class={'mt7'}>{statuList[row.useStatus as keyof typeof statuList]}</NTag>;
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ key: 'lockOrderId',
|
|
|
|
|
+ title: '订单号',
|
|
|
|
|
+ align: 'center'
|
|
|
|
|
+ }
|
|
|
|
|
+];
|
|
|
|
|
+
|
|
|
|
|
+function handleRecord(id: any) {
|
|
|
|
|
+ couponId.value = id;
|
|
|
|
|
+ openModal();
|
|
|
|
|
+ getCount();
|
|
|
|
|
+}
|
|
|
|
|
+async function validatePrice(_: any, value: any) {
|
|
|
|
|
+ const form = await getModalFormValue();
|
|
|
|
|
+ if (value <= form.discountMoney) {
|
|
|
|
|
+ console.log(1111111);
|
|
|
|
|
+
|
|
|
|
|
+ return; // 验证通过时返回undefined
|
|
|
|
|
+ }
|
|
|
|
|
+ console.log(2222222222);
|
|
|
|
|
+
|
|
|
|
|
+ throw new Error('应小于等于面额'); // 验证失败时抛出错误
|
|
|
|
|
+}
|
|
|
|
|
+async function validateDiscountMoney(_: any, value: any) {
|
|
|
|
|
+ const form = await getModalFormValue();
|
|
|
|
|
+ if (value < form.amountMoney * 0.5) {
|
|
|
|
|
+ return; // 验证通过时返回undefined
|
|
|
|
|
+ }
|
|
|
|
|
+ throw new Error('需要小于门槛金额*0.5.数值范围0-1000,保留两位小数'); // 验证失败时抛出错误
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+async function edit(row: Api.goods.ShopCategory) {
|
|
|
|
|
+ openModalForm(row);
|
|
|
|
|
+ const data = { ...row, createTime: [row.couponStartTime, row.couponEndTime], inventory: row.inventoryTotal };
|
|
|
|
|
+ // setModalProps({ title: `修改${Number(row.level)}级分类` });
|
|
|
|
|
+ setModalFormValue(data);
|
|
|
|
|
+}
|
|
|
|
|
+function add(row: Api.goods.ShopCategory) {
|
|
|
|
|
+ openModalForm();
|
|
|
|
|
+ console.log(row, 'row-key');
|
|
|
|
|
+ // updateSchema({ field: 'iconUrl', required: true });
|
|
|
|
|
+ // setModalProps({ title: `新增二级分类` });
|
|
|
|
|
+ // setModalFormValue({ parentName: row.name, name: '', parentId: row.id });
|
|
|
|
|
+}
|
|
|
|
|
+function del(row: Api.goods.ShopCategory) {
|
|
|
|
|
+ window.$dialog?.info({
|
|
|
|
|
+ title: '删除活动',
|
|
|
|
|
+ content: '你确定要删除吗?',
|
|
|
|
|
+ positiveText: '确定',
|
|
|
|
|
+ negativeText: '取消',
|
|
|
|
|
+ onPositiveClick: async () => {
|
|
|
|
|
+ const { error } = await delActivity(row.id);
|
|
|
|
|
+ if (!error) {
|
|
|
|
|
+ refresh();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+async function handleSubmit() {
|
|
|
|
|
+ const form = await getModalFormValue();
|
|
|
|
|
+ setSubLoading(false);
|
|
|
|
|
+ form.couponStartTime = form.createTime[0];
|
|
|
|
|
+ form.couponEndTime = form.createTime[1];
|
|
|
|
|
+ delete form.createTime;
|
|
|
|
|
+ if (!form.id) {
|
|
|
|
|
+ const { error } = await fetchAddActivity(form);
|
|
|
|
|
+ if (error) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 修改
|
|
|
|
|
+ const { error } = await fetchEditActivity(form);
|
|
|
|
|
+ if (error) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ closeModalForm();
|
|
|
|
|
+ refresh();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+async function getCount() {
|
|
|
|
|
+ const { data, error } = await fetchReceiveRecordCount({
|
|
|
|
|
+ couponId: couponId.value
|
|
|
|
|
+ });
|
|
|
|
|
+ console.log(3333333333333, data, error);
|
|
|
|
|
+ if (!error && data) {
|
|
|
|
|
+ countObj.value = data;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<template>
|
|
|
|
|
+ <LayoutTable>
|
|
|
|
|
+ <ZTable
|
|
|
|
|
+ :show-table-action="false"
|
|
|
|
|
+ :columns="tableColumns"
|
|
|
|
|
+ :api="fetchGetActivityList"
|
|
|
|
|
+ @register="registerModalTable"
|
|
|
|
|
+ @add="add"
|
|
|
|
|
+ ></ZTable>
|
|
|
|
|
+ <BasicModelForm @register-modal-form="registerModalForm" @submit-form="handleSubmit"></BasicModelForm>
|
|
|
|
|
+
|
|
|
|
|
+ <BasicModal @register="registerModal" @after-leave="refreshModal">
|
|
|
|
|
+ <ZTable
|
|
|
|
|
+ :show-table-action="false"
|
|
|
|
|
+ :columns="ModalColumns"
|
|
|
|
|
+ :api="fetchReceiveRecord"
|
|
|
|
|
+ :default-params="{ couponId }"
|
|
|
|
|
+ @register="registerClaimModalTable"
|
|
|
|
|
+ >
|
|
|
|
|
+ <template #header>
|
|
|
|
|
+ <div class="flex">
|
|
|
|
|
+ <div class="ml-10px">发放数量:{{ countObj.provideNumber }}</div>
|
|
|
|
|
+ <div class="ml-10px">未领取:{{ countObj.unclaimedNumber }}</div>
|
|
|
|
|
+ <div class="ml-10px">领取-未使用:{{ countObj.receiveUnusedNumber }}</div>
|
|
|
|
|
+ <div class="ml-10px">领取-已使用:{{ countObj.receiveUsedNumber }}</div>
|
|
|
|
|
+ <div class="ml-10px">领取-冻结:{{ countObj.receiveFreezeNumber }}</div>
|
|
|
|
|
+ <div class="ml-10px">领取-失效:{{ countObj.receiveFailureNumber }}</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </ZTable>
|
|
|
|
|
+ </BasicModal>
|
|
|
|
|
+ </LayoutTable>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<style scoped></style>
|