|
|
@@ -0,0 +1,939 @@
|
|
|
+<script setup lang="tsx">
|
|
|
+import { computed, nextTick, onMounted, ref, watch } from 'vue';
|
|
|
+import { useRoute, useRouter } from 'vue-router';
|
|
|
+import type { DataTableColumns, FormInst, FormRules } from 'naive-ui';
|
|
|
+import { NForm, NImage, NInput, NSelect, useMessage } from 'naive-ui';
|
|
|
+import {
|
|
|
+ fetchAddType,
|
|
|
+ fetchEditType,
|
|
|
+ fetchFirstChannel,
|
|
|
+ fetchGoodsList,
|
|
|
+ fetchTypeDetail
|
|
|
+} from '@/service/api/member-center/member-type';
|
|
|
+import { fetchGetActivityList } from '@/service/api/operation/coupon-manage';
|
|
|
+import { fetchGetStoreList } from '@/service/api/xsb-manage/store-info';
|
|
|
+import { useTable } from '@/components/zt/Table/hooks/useTable';
|
|
|
+import { useModal } from '@/components/zt/Modal/hooks/useModal';
|
|
|
+import ZUpload from '../../../components/zt/upload/z-upload.vue';
|
|
|
+const router = useRouter();
|
|
|
+const current = ref('A');
|
|
|
+const route = useRoute();
|
|
|
+const formRef = ref<FormInst | null>(null);
|
|
|
+const message = useMessage();
|
|
|
+const disabled = ref(false);
|
|
|
+const loading = ref(false);
|
|
|
+
|
|
|
+const cancelOptions = [
|
|
|
+ { label: '立即生效', value: 'IMMEDIATE' },
|
|
|
+ { label: '次月生效', value: 'NEXT_MONTH' }
|
|
|
+];
|
|
|
+// 1 厂家直冲,2 卖家直发,3 官方直充,4 扫码直充,5 卖家代充,6 卡密
|
|
|
+const rechargeOptions = [
|
|
|
+ { label: '厂家直充', value: 1 },
|
|
|
+ { label: '卖家直发', value: 2 },
|
|
|
+ { label: '官方直充', value: 3 },
|
|
|
+ { label: '扫码直充', value: 4 },
|
|
|
+ { label: '卖家代充', value: 5 },
|
|
|
+ { label: '卡密', value: 6 }
|
|
|
+];
|
|
|
+
|
|
|
+const channelOptions = ref<{ label: string; value: string; id: number }[]>([]);
|
|
|
+
|
|
|
+const model = ref({
|
|
|
+ id: 0,
|
|
|
+ memberName: '',
|
|
|
+ coverImg: '',
|
|
|
+ faceAmount: 0,
|
|
|
+ stock: 0,
|
|
|
+ settleAmount: 0,
|
|
|
+ rechargeType: null,
|
|
|
+ brandName: '市民请集合',
|
|
|
+ businessType: 'XSB',
|
|
|
+ useValidDays: 0,
|
|
|
+ cancelRule: '',
|
|
|
+ useRule: '',
|
|
|
+ rightsDesc: '',
|
|
|
+ openChannelCodes: '',
|
|
|
+ priceChannelId: '',
|
|
|
+ benefitConfigJson: { oilPerLiterDiscount: 0, mallDiscountRate: 0, chargePerKwhDiscount: 0, parkingDiscountRate: 0 },
|
|
|
+ couponConfigJson: [{ couponId: '', count: 1 }] as any,
|
|
|
+ giftConfigJson: [] as any,
|
|
|
+ status: 0
|
|
|
+});
|
|
|
+
|
|
|
+const isCheckedOilPerLiterDiscount = ref(false);
|
|
|
+const isCheckedMallDiscountRate = ref(false);
|
|
|
+const isCheckedChargePerKwhDiscount = ref(false);
|
|
|
+const isCheckedParkingDiscountRate = ref(false);
|
|
|
+const isCheckedCouponConfigJson = ref(false);
|
|
|
+const isCheckedGiftConfigJson = ref(false);
|
|
|
+const isCheckedStock = computed(() => {
|
|
|
+ if (model.value.stock === -1) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+});
|
|
|
+
|
|
|
+const currentChannel = ref<any>();
|
|
|
+
|
|
|
+const rules: FormRules = {
|
|
|
+ memberName: {
|
|
|
+ required: true,
|
|
|
+ trigger: ['blur', 'input'],
|
|
|
+ message: '请输入'
|
|
|
+ },
|
|
|
+ coverImg: {
|
|
|
+ type: 'string',
|
|
|
+ required: true,
|
|
|
+ trigger: ['blur', 'change'],
|
|
|
+ message: '请上传'
|
|
|
+ },
|
|
|
+ faceAmount: {
|
|
|
+ type: 'number',
|
|
|
+ min: 1,
|
|
|
+ max: 100000,
|
|
|
+ required: true,
|
|
|
+ trigger: ['blur', 'change'],
|
|
|
+ message: '请输入'
|
|
|
+ },
|
|
|
+ settleAmount: {
|
|
|
+ min: 1,
|
|
|
+ max: 100000,
|
|
|
+ type: 'number',
|
|
|
+ required: true,
|
|
|
+ trigger: ['blur', 'input'],
|
|
|
+ message: '请输入'
|
|
|
+ },
|
|
|
+ brandName: {
|
|
|
+ type: 'string',
|
|
|
+ required: true,
|
|
|
+ trigger: ['blur', 'change'],
|
|
|
+ message: '请输入'
|
|
|
+ },
|
|
|
+ rechargeType: {
|
|
|
+ type: 'number',
|
|
|
+ required: true,
|
|
|
+ trigger: ['blur', 'change'],
|
|
|
+ message: '请选择'
|
|
|
+ },
|
|
|
+ stock: {
|
|
|
+ type: 'number',
|
|
|
+ required: true,
|
|
|
+ trigger: ['blur', 'change'],
|
|
|
+ message: '请输入'
|
|
|
+ },
|
|
|
+ useValidDays: {
|
|
|
+ type: 'number',
|
|
|
+ required: true,
|
|
|
+ trigger: ['blur', 'change'],
|
|
|
+ message: '请输入'
|
|
|
+ },
|
|
|
+ cancelRule: {
|
|
|
+ required: true,
|
|
|
+ trigger: ['blur', 'change'],
|
|
|
+ message: '请选择'
|
|
|
+ },
|
|
|
+ useRule: {
|
|
|
+ required: true,
|
|
|
+ trigger: ['blur', 'change'],
|
|
|
+ message: '请输入'
|
|
|
+ },
|
|
|
+ openChannelCodes: {
|
|
|
+ required: true,
|
|
|
+ trigger: ['blur', 'change'],
|
|
|
+ message: '请输入'
|
|
|
+ },
|
|
|
+ priceChannelId: {
|
|
|
+ type: 'number',
|
|
|
+ required: true,
|
|
|
+ trigger: ['blur', 'change'],
|
|
|
+ message: '请输入'
|
|
|
+ },
|
|
|
+ benefitConfigJson: {
|
|
|
+ required: true,
|
|
|
+ trigger: ['blur', 'change'],
|
|
|
+ message: '请输入'
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+interface ProductItem {
|
|
|
+ goodsImg: string;
|
|
|
+ goodsName: string;
|
|
|
+ goodsCode: string;
|
|
|
+ name?: string;
|
|
|
+}
|
|
|
+
|
|
|
+const columns: DataTableColumns<ProductItem> = [
|
|
|
+ {
|
|
|
+ type: 'selection',
|
|
|
+ multiple: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'hbSkuId',
|
|
|
+ title: '商品ID',
|
|
|
+ align: 'left',
|
|
|
+ width: 200
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'skuCode',
|
|
|
+ title: '商品编码',
|
|
|
+ align: 'center',
|
|
|
+ width: 120,
|
|
|
+ ellipsis: {
|
|
|
+ tooltip: true
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ {
|
|
|
+ key: 'pic',
|
|
|
+ title: '商品图片',
|
|
|
+ align: 'center',
|
|
|
+ width: 120,
|
|
|
+ render: (row: any) => {
|
|
|
+ return <n-image src={row.pic} width={60} height={60}></n-image>;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ {
|
|
|
+ key: 'prodName',
|
|
|
+ title: '商品名称',
|
|
|
+ align: 'center',
|
|
|
+ width: 120,
|
|
|
+ ellipsis: {
|
|
|
+ tooltip: true
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'shopSkuStocks',
|
|
|
+ title: '库存',
|
|
|
+ align: 'center',
|
|
|
+ width: 120,
|
|
|
+ ellipsis: {
|
|
|
+ tooltip: true
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'channelVOS',
|
|
|
+ title: '价格',
|
|
|
+ align: 'center',
|
|
|
+ width: 120,
|
|
|
+ render: (row: any) => {
|
|
|
+ return (
|
|
|
+ console.log(currentChannel.value, 'currentChannel'),
|
|
|
+ (
|
|
|
+ <div>
|
|
|
+ {row.channelVOS.map((it: Api.government.ChannelVO) => {
|
|
|
+ if (it.channelId == currentChannel.value?.id) {
|
|
|
+ return (
|
|
|
+ <div>
|
|
|
+ {it.channelName}:¥{it.price}
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ })}
|
|
|
+ </div>
|
|
|
+ )
|
|
|
+ );
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'shopName',
|
|
|
+ title: '门店名称',
|
|
|
+ align: 'center',
|
|
|
+ width: 120,
|
|
|
+ ellipsis: {
|
|
|
+ tooltip: true
|
|
|
+ }
|
|
|
+ }
|
|
|
+];
|
|
|
+
|
|
|
+const [registerModalTable, { refresh, getTableCheckedRowKeys, getTableData, setFieldsValue, setTableCheckedRowKeys }] =
|
|
|
+ useTable({
|
|
|
+ searchFormConfig: {
|
|
|
+ schemas: [
|
|
|
+ // {
|
|
|
+ // label: '销售渠道',
|
|
|
+ // component: 'ApiSelect',
|
|
|
+ // field: 'channelNo',
|
|
|
+ // componentProps: {
|
|
|
+ // api: fetchFirstChannel,
|
|
|
+ // resultFeild: 'data',
|
|
|
+ // labelFeild: 'channelName',
|
|
|
+ // valueFeild: 'channelNo'
|
|
|
+ // }
|
|
|
+ // },
|
|
|
+ {
|
|
|
+ label: '销售渠道',
|
|
|
+ component: 'NSelect',
|
|
|
+ field: 'channelNo',
|
|
|
+ render: form => {
|
|
|
+ return (
|
|
|
+ <NSelect
|
|
|
+ v-model:value={form.model.channelNo}
|
|
|
+ placeholder="请选择销售渠道"
|
|
|
+ options={channelOptions.value}
|
|
|
+ on-update:value={changeChannel}
|
|
|
+ ></NSelect>
|
|
|
+ );
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '门店名称',
|
|
|
+ component: 'ApiSelect',
|
|
|
+ field: 'shopId',
|
|
|
+ componentProps: {
|
|
|
+ api: fetchGetStoreList,
|
|
|
+ resultFeild: 'data.list',
|
|
|
+ labelFeild: 'shopName',
|
|
|
+ valueFeild: 'shopId'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '商品名称',
|
|
|
+ component: 'NInput',
|
|
|
+ field: 'skuName',
|
|
|
+ componentProps: {
|
|
|
+ placeholder: '请输入商品名称'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '商品ID',
|
|
|
+ component: 'NInput',
|
|
|
+ field: 'keywords'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '商品编码',
|
|
|
+ component: 'NInput',
|
|
|
+ field: 'skuCode'
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ inline: false,
|
|
|
+ size: 'small',
|
|
|
+ labelPlacement: 'left',
|
|
|
+ isFull: false
|
|
|
+ },
|
|
|
+ tableConfig: {
|
|
|
+ keyField: 'skuId',
|
|
|
+ title: '商品列表',
|
|
|
+ showAddButton: false,
|
|
|
+ minHeight: 650
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+const [registerModal, { openModal, closeModal, setModalProps }] = useModal({
|
|
|
+ title: `商品选择(已选${model.value.giftConfigJson.length}项)`,
|
|
|
+ height: 800,
|
|
|
+ width: 1200
|
|
|
+});
|
|
|
+watch(
|
|
|
+ () => getTableCheckedRowKeys(),
|
|
|
+ val => {
|
|
|
+ setModalProps({
|
|
|
+ title: `商品选择(已选${val.length}项)`
|
|
|
+ });
|
|
|
+ }
|
|
|
+);
|
|
|
+function changeChannel(value: string, opt: any) {
|
|
|
+ setFieldsValue({
|
|
|
+ channelNo: value
|
|
|
+ });
|
|
|
+ console.log(11111111111, value, opt);
|
|
|
+ currentChannel.value = opt;
|
|
|
+}
|
|
|
+function getChannel() {
|
|
|
+ fetchFirstChannel().then(res => {
|
|
|
+ channelOptions.value = res.data.map((item: any) => {
|
|
|
+ return {
|
|
|
+ label: item.channelName,
|
|
|
+ value: item.channelNo,
|
|
|
+ id: item.id
|
|
|
+ };
|
|
|
+ });
|
|
|
+ currentChannel.value = channelOptions.value[0];
|
|
|
+
|
|
|
+ console.log(res);
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+getChannel();
|
|
|
+function handleValidateButtonClick(e: MouseEvent) {
|
|
|
+ e.preventDefault();
|
|
|
+ formRef.value?.validate(async errors => {
|
|
|
+ if (!errors) {
|
|
|
+ loading.value = true;
|
|
|
+
|
|
|
+ const form = JSON.parse(JSON.stringify(model.value));
|
|
|
+ let rightsDesc = '';
|
|
|
+ let num = 0;
|
|
|
+
|
|
|
+ // 除了权益配置 加油 充电 停车 快消品数据
|
|
|
+ if (!isCheckedChargePerKwhDiscount.value) {
|
|
|
+ delete form.benefitConfigJson.chargePerKwhDiscount;
|
|
|
+ } else {
|
|
|
+ num += 1;
|
|
|
+ rightsDesc += `${num}、全省贵阳城投充电桩充电优惠${form.benefitConfigJson.chargePerKwhDiscount}元/度;\n `;
|
|
|
+ }
|
|
|
+ if (!isCheckedOilPerLiterDiscount.value) {
|
|
|
+ delete form.benefitConfigJson.oilPerLiterDiscount;
|
|
|
+ } else {
|
|
|
+ num += 1;
|
|
|
+ rightsDesc += `${num}、全省中国石化加油站加油优惠${form.benefitConfigJson.oilPerLiterDiscount}元/升;\n `;
|
|
|
+ }
|
|
|
+ if (!isCheckedMallDiscountRate.value) {
|
|
|
+ delete form.benefitConfigJson.mallDiscountRate;
|
|
|
+ } else {
|
|
|
+ num += 1;
|
|
|
+ rightsDesc += `${num}、市民请结合平台超6000+快消品优惠${form.benefitConfigJson.mallDiscountRate}%;\n `;
|
|
|
+ }
|
|
|
+ if (!isCheckedParkingDiscountRate.value) {
|
|
|
+ delete form.benefitConfigJson.parkingDiscountRate;
|
|
|
+ } else {
|
|
|
+ num += 1;
|
|
|
+ rightsDesc += `${num}、全场18000+贵阳城投停车位停车优惠${form.benefitConfigJson.parkingDiscountRate}%;\n `;
|
|
|
+ }
|
|
|
+
|
|
|
+ form.benefitConfigJson = JSON.stringify(form.benefitConfigJson);
|
|
|
+
|
|
|
+ // 处理优惠券配置
|
|
|
+ if (!isCheckedCouponConfigJson.value) {
|
|
|
+ form.couponConfigJson = '';
|
|
|
+ } else {
|
|
|
+ num += 1;
|
|
|
+ form.couponConfigJson = JSON.stringify(form.couponConfigJson);
|
|
|
+ rightsDesc += `${num}、市民请集合本地生活服务平台${form.couponConfigJson.length}张优惠券;\n `;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理赠品配置
|
|
|
+ if (!isCheckedGiftConfigJson.value) {
|
|
|
+ form.giftConfigJson = '';
|
|
|
+ } else {
|
|
|
+ num += 1;
|
|
|
+ form.giftConfigJson = JSON.stringify(form.giftConfigJson);
|
|
|
+ rightsDesc += `${num}、提供${form.giftConfigJson.length}种选1种商品赠送;\n `;
|
|
|
+ }
|
|
|
+ form.rightsDesc = rightsDesc;
|
|
|
+ let res;
|
|
|
+ if (route.query.mode == 'edit') {
|
|
|
+ res = await fetchEditType(form);
|
|
|
+ } else {
|
|
|
+ res = await fetchAddType(form);
|
|
|
+ }
|
|
|
+ loading.value = false;
|
|
|
+ console.log(res);
|
|
|
+
|
|
|
+ if (!res.error) {
|
|
|
+ router.push({
|
|
|
+ path: '/member-center/member-type'
|
|
|
+ });
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ console.log(errors);
|
|
|
+ message.error('验证失败');
|
|
|
+ }
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+async function getDetail() {
|
|
|
+ // 获取详情接口
|
|
|
+ const res = await fetchTypeDetail(route.query.id);
|
|
|
+ if (res.data) {
|
|
|
+ model.value = res.data;
|
|
|
+ if (res.data.benefitConfigJson) {
|
|
|
+ model.value.benefitConfigJson = JSON.parse(res.data.benefitConfigJson);
|
|
|
+ } else {
|
|
|
+ model.value.benefitConfigJson = {
|
|
|
+ oilPerLiterDiscount: 0,
|
|
|
+ mallDiscountRate: 0,
|
|
|
+ chargePerKwhDiscount: 0,
|
|
|
+ parkingDiscountRate: 0
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理配置权益
|
|
|
+ if (model.value.benefitConfigJson.chargePerKwhDiscount) {
|
|
|
+ isCheckedChargePerKwhDiscount.value = true;
|
|
|
+ } else {
|
|
|
+ model.value.benefitConfigJson.chargePerKwhDiscount = 0;
|
|
|
+ }
|
|
|
+ if (model.value.benefitConfigJson.oilPerLiterDiscount) {
|
|
|
+ isCheckedOilPerLiterDiscount.value = true;
|
|
|
+ } else {
|
|
|
+ model.value.benefitConfigJson.oilPerLiterDiscount = 0;
|
|
|
+ console.log('dfasfasf', model.value.benefitConfigJson.oilPerLiterDiscount);
|
|
|
+ }
|
|
|
+ if (model.value.benefitConfigJson.parkingDiscountRate) {
|
|
|
+ isCheckedParkingDiscountRate.value = true;
|
|
|
+ } else {
|
|
|
+ model.value.benefitConfigJson.parkingDiscountRate = 0;
|
|
|
+ }
|
|
|
+ if (model.value.benefitConfigJson.mallDiscountRate) {
|
|
|
+ isCheckedMallDiscountRate.value = true;
|
|
|
+ } else {
|
|
|
+ model.value.benefitConfigJson.mallDiscountRate = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理优惠券配置
|
|
|
+ if (model.value.couponConfigJson) {
|
|
|
+ isCheckedCouponConfigJson.value = true;
|
|
|
+ }
|
|
|
+ if (res.data.couponConfigJson) {
|
|
|
+ model.value.couponConfigJson = JSON.parse(res.data.couponConfigJson);
|
|
|
+ } else {
|
|
|
+ model.value.couponConfigJson = [];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理赠品配置
|
|
|
+ if (model.value.giftConfigJson) {
|
|
|
+ isCheckedGiftConfigJson.value = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (res.data.giftConfigJson) {
|
|
|
+ model.value.giftConfigJson = JSON.parse(res.data.giftConfigJson);
|
|
|
+ } else {
|
|
|
+ model.value.giftConfigJson = [];
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+async function handleAdd(type: string) {
|
|
|
+ if (type === 'A') {
|
|
|
+ // 添加新的优惠券配置项
|
|
|
+ model.value.couponConfigJson.push({
|
|
|
+ couponId: null,
|
|
|
+ count: null
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ current.value = type;
|
|
|
+ openModal();
|
|
|
+ await nextTick();
|
|
|
+ setFieldsValue({
|
|
|
+ channelNo: channelOptions.value[0]?.value
|
|
|
+ });
|
|
|
+ console.log(11111111111, channelOptions.value[0]?.value);
|
|
|
+
|
|
|
+ await nextTick();
|
|
|
+ setTimeout(() => {
|
|
|
+ refresh();
|
|
|
+ }, 1000);
|
|
|
+ if (model.value.giftConfigJson.length) {
|
|
|
+ const selectedKeys = model.value.giftConfigJson.map((item: any) => item.skuId);
|
|
|
+ setTableCheckedRowKeys(selectedKeys);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 商品项去重:根据 skuId + shopId 唯一判断
|
|
|
+ * @param {Array} list 原始数组(你的结构)
|
|
|
+ * @returns {Array} 去重后的新数组
|
|
|
+ */
|
|
|
+function uniqueGoodsList(list: any[]) {
|
|
|
+ // 用 Map 存储唯一键:skuId_shopId
|
|
|
+ const map = new Map();
|
|
|
+
|
|
|
+ // 遍历数组,保留【最后一次】出现的项
|
|
|
+ list.forEach((item: any) => {
|
|
|
+ // 组合唯一标识
|
|
|
+ const key = `${item.skuId}_${item.shopId}`;
|
|
|
+ map.set(key, item);
|
|
|
+ });
|
|
|
+
|
|
|
+ // 转成数组返回
|
|
|
+ return Array.from(map.values());
|
|
|
+}
|
|
|
+function choose() {
|
|
|
+ const keys = getTableCheckedRowKeys();
|
|
|
+ const data = getTableData();
|
|
|
+ closeModal();
|
|
|
+
|
|
|
+ data.forEach(item => {
|
|
|
+ keys.forEach((key: any) => {
|
|
|
+ if (item.skuId === key) {
|
|
|
+ model.value.giftConfigJson.push({
|
|
|
+ skuId: item.skuId,
|
|
|
+ quantity: 1,
|
|
|
+ shopId: item.shopId,
|
|
|
+ channelId: 1,
|
|
|
+ skuName: item.skuName,
|
|
|
+ skuCode: item.skuCode,
|
|
|
+ specName: '-',
|
|
|
+ pic: item.pic,
|
|
|
+ stock: item.shopSkuStocks
|
|
|
+ });
|
|
|
+ model.value.giftConfigJson = uniqueGoodsList(model.value.giftConfigJson);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ console.log(keys, '选择的商品', data);
|
|
|
+}
|
|
|
+
|
|
|
+function handleDelete(type: string, index: number) {
|
|
|
+ if (type === 'A') {
|
|
|
+ if (model.value.couponConfigJson.length == 1) {
|
|
|
+ window.$message?.error('请至少保留一个优惠券配置项');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 删除优惠券配置项
|
|
|
+ model.value.couponConfigJson.splice(index, 1);
|
|
|
+ } else {
|
|
|
+ model.value.giftConfigJson.splice(index, 1);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function handleCheckedChange(checked: boolean) {
|
|
|
+ if (checked) {
|
|
|
+ model.value.stock = -1; // 不限制库存时,设置stock为-1
|
|
|
+ } else {
|
|
|
+ model.value.stock = 0; // 恢复默认库存值
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ if (route.query.id) {
|
|
|
+ if (route.query.mode === 'detail') {
|
|
|
+ disabled.value = true;
|
|
|
+ }
|
|
|
+ getDetail();
|
|
|
+ }
|
|
|
+ console.log(route.query);
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <div class="edit-health-goods pl-20px pt-20px">
|
|
|
+ <NForm
|
|
|
+ ref="formRef"
|
|
|
+ :model="model"
|
|
|
+ :rules="rules"
|
|
|
+ label-placement="left"
|
|
|
+ label-width="100px"
|
|
|
+ require-mark-placement="right-hanging"
|
|
|
+ size="medium"
|
|
|
+ class="max-w-840px"
|
|
|
+ :disabled="disabled"
|
|
|
+ >
|
|
|
+ <div class="font-600">基本信息</div>
|
|
|
+ <NFormItem label="会员名称" path="memberName">
|
|
|
+ <div class="w-100%">
|
|
|
+ <NInput v-model:value="model.memberName" :maxlength="20" placeholder="" />
|
|
|
+ <div class="text-12px">最多支持20个汉字;</div>
|
|
|
+ </div>
|
|
|
+ </NFormItem>
|
|
|
+ <NFormItem label="主图" path="coverImg">
|
|
|
+ <ZUpload v-model:value="model.coverImg" :max="1"></ZUpload>
|
|
|
+ </NFormItem>
|
|
|
+ <NFormItem label="面额(元)" path="faceAmount">
|
|
|
+ <div class="w-100%">
|
|
|
+ <NInputNumber v-model:value="model.faceAmount" :precision="2" />
|
|
|
+ <div class="text-12px">数值范围0-100000,保留两位小数;</div>
|
|
|
+ </div>
|
|
|
+ </NFormItem>
|
|
|
+ <NFormItem label="库存" path="stock">
|
|
|
+ <div class="w-100%">
|
|
|
+ <NInputNumber v-model:value="model.stock" :min="1" :disabled="isCheckedStock" :max="100000" :precision="0" />
|
|
|
+ <NCheckbox class="ml-6px" :checked="isCheckedStock" @update:checked="handleCheckedChange">不限制</NCheckbox>
|
|
|
+ <div class="text-12px">整数,数值范围1-100000</div>
|
|
|
+ </div>
|
|
|
+ </NFormItem>
|
|
|
+
|
|
|
+ <NFormItem label="结算价(元)" path="settleAmount">
|
|
|
+ <div class="w-100%">
|
|
|
+ <NInputNumber v-model:value="model.settleAmount" :min="0" :max="model.faceAmount || 100000" :precision="2" />
|
|
|
+ <div class="text-12px">需小于等于面额金额。数值范围0-100000,保留两位小数;</div>
|
|
|
+ </div>
|
|
|
+ </NFormItem>
|
|
|
+ <NFormItem label="充值类型" path="rechargeType">
|
|
|
+ <NSelect v-model:value="model.rechargeType" placeholder="" :options="rechargeOptions" />
|
|
|
+ </NFormItem>
|
|
|
+ <NFormItem label="品牌" path="brandName">
|
|
|
+ <NInput v-model:value="model.brandName" placeholder="" />
|
|
|
+ </NFormItem>
|
|
|
+ <div class="font-600">权益配置</div>
|
|
|
+ <div class="my-6px text-12px">全省中石化加油优惠</div>
|
|
|
+ <div class="mb-20px border rounded-16px border-dashed pt-24px">
|
|
|
+ <NFormItem
|
|
|
+ label="每升立减"
|
|
|
+ path="benefitConfigJson.oilPerLiterDiscount"
|
|
|
+ :rule="
|
|
|
+ isCheckedOilPerLiterDiscount ? [{ type: 'number', required: true, message: '请输入', trigger: 'blur' }] : []
|
|
|
+ "
|
|
|
+ >
|
|
|
+ <div>
|
|
|
+ <div class="flex items-center">
|
|
|
+ <NInputNumber
|
|
|
+ v-model:value="model.benefitConfigJson.oilPerLiterDiscount"
|
|
|
+ :disabled="!isCheckedOilPerLiterDiscount"
|
|
|
+ :precision="2"
|
|
|
+ :min="0"
|
|
|
+ :max="50"
|
|
|
+ />
|
|
|
+ 元
|
|
|
+ <div class="ml-10px text-12px">(保留2位小数,范围0-50)</div>
|
|
|
+ </div>
|
|
|
+ <div class="mt-6px">
|
|
|
+ <NCheckbox v-model:checked="isCheckedOilPerLiterDiscount" class="ml-6px">启用该权益</NCheckbox>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </NFormItem>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="my-6px text-12px">市民请集合平台快消品</div>
|
|
|
+ <div class="mb-20px border rounded-16px border-dashed pt-24px">
|
|
|
+ <NFormItem
|
|
|
+ label="折扣率"
|
|
|
+ path="benefitConfigJson.mallDiscountRate"
|
|
|
+ :rule="
|
|
|
+ isCheckedMallDiscountRate ? [{ type: 'number', required: true, message: '请输入', trigger: 'blur' }] : []
|
|
|
+ "
|
|
|
+ >
|
|
|
+ <div>
|
|
|
+ <div class="flex items-center">
|
|
|
+ <NInputNumber
|
|
|
+ v-model:value="model.benefitConfigJson.mallDiscountRate"
|
|
|
+ :disabled="!isCheckedMallDiscountRate"
|
|
|
+ :precision="0"
|
|
|
+ :min="0"
|
|
|
+ :max="100"
|
|
|
+ />
|
|
|
+ %
|
|
|
+ <div class="ml-10px text-12px">(输入95表示9.5折,范围0-100)</div>
|
|
|
+ </div>
|
|
|
+ <div class="mt-6px">
|
|
|
+ <NCheckbox v-model:checked="isCheckedMallDiscountRate" class="ml-6px">启用该权益</NCheckbox>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </NFormItem>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="my-6px text-12px">贵阳城投充电桩优惠</div>
|
|
|
+ <div class="mb-20px border rounded-16px border-dashed pt-24px">
|
|
|
+ <NFormItem
|
|
|
+ label="每度电立减"
|
|
|
+ path="benefitConfigJson.chargePerKwhDiscount"
|
|
|
+ :rule="
|
|
|
+ isCheckedChargePerKwhDiscount
|
|
|
+ ? [{ type: 'number', required: true, message: '请输入', trigger: 'blur' }]
|
|
|
+ : []
|
|
|
+ "
|
|
|
+ >
|
|
|
+ <div>
|
|
|
+ <div class="flex items-center">
|
|
|
+ <NInputNumber
|
|
|
+ v-model:value="model.benefitConfigJson.chargePerKwhDiscount"
|
|
|
+ :disabled="!isCheckedChargePerKwhDiscount"
|
|
|
+ :precision="2"
|
|
|
+ :min="0"
|
|
|
+ :max="50"
|
|
|
+ />
|
|
|
+ 元
|
|
|
+ <div class="ml-10px text-12px">(保留2位小数,范围0-50)</div>
|
|
|
+ </div>
|
|
|
+ <div class="mt-6px">
|
|
|
+ <NCheckbox v-model:checked="isCheckedChargePerKwhDiscount" class="ml-6px">启用该权益</NCheckbox>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </NFormItem>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="my-6px text-12px">贵阳城投停车位停车优惠</div>
|
|
|
+ <div class="mb-20px border rounded-16px border-dashed pt-24px">
|
|
|
+ <NFormItem
|
|
|
+ label="折扣率"
|
|
|
+ path="benefitConfigJson.parkingDiscountRate"
|
|
|
+ :rule="
|
|
|
+ isCheckedParkingDiscountRate ? [{ type: 'number', required: true, message: '请输入', trigger: 'blur' }] : []
|
|
|
+ "
|
|
|
+ >
|
|
|
+ <div>
|
|
|
+ <div class="flex items-center">
|
|
|
+ <NInputNumber
|
|
|
+ v-model:value="model.benefitConfigJson.parkingDiscountRate"
|
|
|
+ :disabled="!isCheckedParkingDiscountRate"
|
|
|
+ :precision="0"
|
|
|
+ :min="0"
|
|
|
+ :max="100"
|
|
|
+ />
|
|
|
+ %
|
|
|
+ <div class="ml-10px text-12px">(输入95表示9.5折,范围0-100)</div>
|
|
|
+ </div>
|
|
|
+ <div class="mt-6px">
|
|
|
+ <NCheckbox v-model:checked="isCheckedParkingDiscountRate" class="ml-6px">启用该权益</NCheckbox>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </NFormItem>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="my-6px text-12px">市民请集合平台优惠券</div>
|
|
|
+ <div class="mb-20px border rounded-16px border-dashed pt-24px">
|
|
|
+ <NButton class="mb-20px ml-30px" icon-placement="left" secondary strong @click="handleAdd('A')">
|
|
|
+ <template #icon>
|
|
|
+ <icon-material-symbols:add-circle class="text-icon" />
|
|
|
+ </template>
|
|
|
+ 添加优惠券
|
|
|
+ </NButton>
|
|
|
+ <div v-for="(item, index) in model.couponConfigJson" :key="index" class="flex">
|
|
|
+ <NFormItem
|
|
|
+ label="优惠券"
|
|
|
+ :path="`couponConfigJson[${index}].couponId`"
|
|
|
+ :rule="isCheckedCouponConfigJson ? [{ required: true, message: '请选择优惠券', trigger: 'change' }] : []"
|
|
|
+ >
|
|
|
+ <!-- <NSelect v-model:value="item.couponId" class="min-w-170px" placeholder="" :options="options" /> -->
|
|
|
+ <ApiSelect
|
|
|
+ v-model:value="item.couponId"
|
|
|
+ class="min-w-170px"
|
|
|
+ :api="fetchGetActivityList"
|
|
|
+ result-feild="data.list"
|
|
|
+ label-field="activityName"
|
|
|
+ value-field="id"
|
|
|
+ ></ApiSelect>
|
|
|
+ </NFormItem>
|
|
|
+
|
|
|
+ <NFormItem
|
|
|
+ label="发放张数"
|
|
|
+ :path="`couponConfigJson[${index}].count`"
|
|
|
+ :rule="
|
|
|
+ isCheckedCouponConfigJson
|
|
|
+ ? [{ required: true, message: '请选择优惠券', trigger: 'change', type: 'number' }]
|
|
|
+ : []
|
|
|
+ "
|
|
|
+ >
|
|
|
+ <NInputNumber v-model:value="item.count" :precision="0" :min="0" :max="100000" />
|
|
|
+ 张
|
|
|
+ <div class="ml-10px text-12px">(整数,范围0-100000)</div>
|
|
|
+ </NFormItem>
|
|
|
+ <NButton
|
|
|
+ class="mb-20px ml-30px"
|
|
|
+ icon-placement="left"
|
|
|
+ secondary
|
|
|
+ strong
|
|
|
+ @click="handleDelete('A', index as number)"
|
|
|
+ >
|
|
|
+ <template #icon>
|
|
|
+ <icon-icon-park-solid:reduce-one class="text-icon" />
|
|
|
+ </template>
|
|
|
+ </NButton>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="mt-6px">
|
|
|
+ <NCheckbox v-model:checked="isCheckedCouponConfigJson" class="ml-100px">启用该权益</NCheckbox>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="my-6px text-12px">自选赠品</div>
|
|
|
+ <div class="mb-20px border rounded-16px border-dashed pt-24px">
|
|
|
+ <NButton class="mb-20px ml-30px" icon-placement="left" secondary strong @click="handleAdd('B')">
|
|
|
+ <template #icon>
|
|
|
+ <icon-material-symbols:add-circle class="text-icon" />
|
|
|
+ </template>
|
|
|
+ 添加商品
|
|
|
+ </NButton>
|
|
|
+ <NFormItem
|
|
|
+ path="giftConfigJson"
|
|
|
+ class="ml-60px"
|
|
|
+ :rule="
|
|
|
+ isCheckedGiftConfigJson
|
|
|
+ ? [{ required: true, type: 'array', min: 1, message: '请选择商品', trigger: 'change' }]
|
|
|
+ : []
|
|
|
+ "
|
|
|
+ >
|
|
|
+ <div class="flex flex-wrap">
|
|
|
+ <div
|
|
|
+ v-for="(item, index) in model.giftConfigJson"
|
|
|
+ :key="index"
|
|
|
+ class="relative mb-20px mr-20px flex border-1px rounded-8px p-10px pr-40px"
|
|
|
+ >
|
|
|
+ <NImage :src="item.pic" class="h90px w90px"></NImage>
|
|
|
+ <div class="ml-10px flex-1 text-12px">
|
|
|
+ <div class="w-200px overflow-hidden text-ellipsis text-nowrap">{{ item.skuName }}</div>
|
|
|
+ <div>商品编码:{{ item.skuCode }}</div>
|
|
|
+ <div>规格:{{ item.specName }}</div>
|
|
|
+ <div>库存:{{ item.stock }}</div>
|
|
|
+ <div class="flex items-center">
|
|
|
+ 赠送数量:
|
|
|
+ <NInputNumber v-model:value="item.quantity" class="w-100px" :precision="0" :min="1" :max="100" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <NButton
|
|
|
+ class="absolute bottom-10px right-10px text-12px"
|
|
|
+ text
|
|
|
+ @click="handleDelete('B', index as number)"
|
|
|
+ >
|
|
|
+ 删除
|
|
|
+ </NButton>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </NFormItem>
|
|
|
+
|
|
|
+ <div class="mt-6px">
|
|
|
+ <NCheckbox v-model:checked="isCheckedGiftConfigJson" class="ml-100px">启用该权益</NCheckbox>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="font-600">其他条件</div>
|
|
|
+
|
|
|
+ <NFormItem label="开发渠道" path="openChannelCodes">
|
|
|
+ <DictSelect v-model:value="model.openChannelCodes" dict-code="open_channel" :immediate="true"></DictSelect>
|
|
|
+ </NFormItem>
|
|
|
+
|
|
|
+ <NFormItem label="价格体系" path="priceChannelId">
|
|
|
+ <div>
|
|
|
+ <ApiSelect
|
|
|
+ v-model:value="model.priceChannelId"
|
|
|
+ :api="fetchFirstChannel"
|
|
|
+ label-field="channelName"
|
|
|
+ value-field="id"
|
|
|
+ ></ApiSelect>
|
|
|
+ <div class="mt-10px text-12px">用哪个企业的价格体系来进行计算;</div>
|
|
|
+ </div>
|
|
|
+ </NFormItem>
|
|
|
+
|
|
|
+ <NFormItem label="使用有效期" path="useValidDays">
|
|
|
+ 领取之日起
|
|
|
+ <NInputNumber v-model:value="model.useValidDays" />
|
|
|
+ 日有效
|
|
|
+ </NFormItem>
|
|
|
+
|
|
|
+ <NFormItem label="取消规则" path="cancelRule">
|
|
|
+ <div>
|
|
|
+ <NSelect v-model:value="model.cancelRule" placeholder="" :options="cancelOptions" />
|
|
|
+ <div class="mt-10px text-12px">次月生效:取消成功后,下个自然月生效;立即生效,取消成功后,立即生效;</div>
|
|
|
+ </div>
|
|
|
+ </NFormItem>
|
|
|
+
|
|
|
+ <NFormItem label="使用规则" path="useRule">
|
|
|
+ <NInput v-model:value="model.useRule" type="textarea" show-count :maxlength="500" placeholder="" />
|
|
|
+ </NFormItem>
|
|
|
+ <NFormItem label="状态">
|
|
|
+ <NSwitch v-model:value="model.status" :unchecked-value="0" :checked-value="1" />
|
|
|
+ </NFormItem>
|
|
|
+ <div v-if="!disabled" class="flex justify-end">
|
|
|
+ <NButton round type="primary" :loading="loading" @click="handleValidateButtonClick">保存</NButton>
|
|
|
+ </div>
|
|
|
+ </NForm>
|
|
|
+
|
|
|
+ <BasicModal @register="registerModal" @ok="choose">
|
|
|
+ <LayoutTable>
|
|
|
+ <ZTable
|
|
|
+ :immediate="false"
|
|
|
+ :show-table-action="false"
|
|
|
+ :columns="columns"
|
|
|
+ :api="fetchGoodsList"
|
|
|
+ :default-params="{ channelCode: 'XSB' }"
|
|
|
+ default-params-not-reset="channelNo"
|
|
|
+ @register="registerModalTable"
|
|
|
+ ></ZTable>
|
|
|
+ </LayoutTable>
|
|
|
+ </BasicModal>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+::v-deep .n-form-item-blank {
|
|
|
+ z-index: 6 !important;
|
|
|
+}
|
|
|
+.edit-health-goods {
|
|
|
+ background: #fff;
|
|
|
+}
|
|
|
+</style>
|