diff --git a/src/api/mall/promotion/coupon/coupon.ts b/src/api/mall/promotion/coupon/coupon.ts index 565b86f7..2ebff5da 100755 --- a/src/api/mall/promotion/coupon/coupon.ts +++ b/src/api/mall/promotion/coupon/coupon.ts @@ -16,3 +16,11 @@ export const getCouponPage = async (params: PageParam) => { params: params }) } + +// 发送优惠券 +export const sendCoupon = async (data: any) => { + return request.post({ + url: '/promotion/coupon/send', + data: data + }) +} diff --git a/src/api/mall/promotion/coupon/couponTemplate.ts b/src/api/mall/promotion/coupon/couponTemplate.ts index 6a58876e..243e22ee 100755 --- a/src/api/mall/promotion/coupon/couponTemplate.ts +++ b/src/api/mall/promotion/coupon/couponTemplate.ts @@ -9,7 +9,7 @@ export interface CouponTemplateVO { takeType: number usePrice: number productScope: number - productSpuIds: string + productScopeValues: number[] validityType: number validStartTime: Date validEndTime: Date diff --git a/src/api/mall/trade/order/index.ts b/src/api/mall/trade/order/index.ts index 9413b73c..d4a22944 100644 --- a/src/api/mall/trade/order/index.ts +++ b/src/api/mall/trade/order/index.ts @@ -15,11 +15,11 @@ export interface OrderVO { cancelTime?: Date | null // 订单取消时间 cancelType?: number | null // 取消类型 remark?: string // 商家备注 - payOrderId: number | null // 支付订单编号 + payOrderId?: number | null // 支付订单编号 payed?: boolean // 是否已支付 payTime?: Date | null // 付款时间 payChannelCode?: string // 支付渠道 - originalPrice?: number | null // 商品原价(总) + totalPrice?: number | null // 商品原价(总) orderPrice?: number | null // 订单原价(总) discountPrice?: number | null // 订单优惠(总) deliveryPrice?: number | null // 运费金额 @@ -44,12 +44,19 @@ export interface OrderVO { pointPrice?: number | null // 积分抵扣的金额 receiverAreaName?: string //收件人地区名字 items?: OrderItemRespVO[] // 订单项列表 - //用户信息 + // 用户信息 user?: { id?: number | null nickname?: string avatar?: string } + // 订单操作日志 + orderLog: orderLog[] +} + +export interface orderLog { + content?: string + createTime?: Date } export interface OrderItemRespVO { @@ -94,6 +101,11 @@ export const getOrder = async (id: number | null) => { return await request.get({ url: `/trade/order/get-detail?id=` + id }) } +// 查询交易订单物流详情 +export const getExpressTrackList = async (id: number | null) => { + return await request.get({ url: `/trade/order/get-express-track-list?id=` + id }) +} + export interface DeliveryVO { id: number // 订单编号 logisticsId: number | null // 物流公司编号 diff --git a/src/utils/constants.ts b/src/utils/constants.ts index cd346a5c..8d783635 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -209,17 +209,39 @@ export const CouponTemplateValidityTypeEnum = { } } +/** + * 优惠劵模板的领取方式的枚举 + */ +export const CouponTemplateTakeTypeEnum = { + USER: { + type: 1, + name: '直接领取' + }, + ADMIN: { + type: 2, + name: '指定发放' + }, + REGISTER: { + type: 3, + name: '新人券' + } +} + /** * 营销的商品范围枚举 */ export const PromotionProductScopeEnum = { ALL: { scope: 1, - name: '全部商品参与' + name: '通用劵' }, SPU: { scope: 2, - name: '指定商品参与' + name: '商品劵' + }, + CATEGORY: { + scope: 3, + name: '品类劵' } } diff --git a/src/views/mall/product/brand/index.vue b/src/views/mall/product/brand/index.vue index 9250befd..c89fe520 100644 --- a/src/views/mall/product/brand/index.vue +++ b/src/views/mall/product/brand/index.vue @@ -59,7 +59,7 @@ diff --git a/src/views/mall/product/category/components/ProductCategorySelect.vue b/src/views/mall/product/category/components/ProductCategorySelect.vue new file mode 100644 index 00000000..179a6a3b --- /dev/null +++ b/src/views/mall/product/category/components/ProductCategorySelect.vue @@ -0,0 +1,47 @@ + + diff --git a/src/views/mall/product/category/index.vue b/src/views/mall/product/category/index.vue index a2adfe7f..27ea5368 100644 --- a/src/views/mall/product/category/index.vue +++ b/src/views/mall/product/category/index.vue @@ -38,7 +38,7 @@ diff --git a/src/views/mall/product/comment/index.vue b/src/views/mall/product/comment/index.vue index 1b0745ba..7c0737f5 100644 --- a/src/views/mall/product/comment/index.vue +++ b/src/views/mall/product/comment/index.vue @@ -115,7 +115,7 @@ :formatter="dateFormatter" width="170" /> - + @@ -175,7 +185,7 @@ import { propTypes } from '@/utils/propTypes' import { checkSelectedNode, defaultProps, handleTree, treeToString } from '@/utils/tree' import { createImageViewer } from '@/components/ImageViewer' import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { PropertyAndValues, SkuList } from '@/views/mall/product/spu/components/index.ts' +import { getPropertyList, RuleConfig, SkuList } from '@/views/mall/product/spu/components/index.ts' import ProductAttributes from './ProductAttributes.vue' import ProductPropertyAddForm from './ProductPropertyAddForm.vue' import { basicInfoSchema } from './spu.data' @@ -186,6 +196,30 @@ import * as ExpressTemplateApi from '@/api/mall/trade/delivery/expressTemplate' defineOptions({ name: 'ProductSpuBasicInfoForm' }) +// sku 相关属性校验规则 +const ruleConfig: RuleConfig[] = [ + { + name: 'stock', + rule: (arg) => arg >= 1, + message: '商品库存必须大于等于 1 !!!' + }, + { + name: 'price', + rule: (arg) => arg >= 0.01, + message: '商品销售价格必须大于等于 0.01 !!!' + }, + { + name: 'marketPrice', + rule: (arg) => arg >= 0.01, + message: '商品市场价格必须大于等于 0.01 !!!' + }, + { + name: 'costPrice', + rule: (arg) => arg >= 0.01, + message: '商品成本价格必须大于等于 0.01 !!!' + } +] + // ====== 商品详情相关操作 ====== const { allSchemas } = useCrudSchemas(basicInfoSchema) /** 商品图预览 */ @@ -203,34 +237,6 @@ const imagePreview = (args) => { }) } -/** - * 获得商品的规格列表 - * - * @param spu - * @return PropertyAndValues 规格列表 - */ -const getPropertyList = (spu: Spu): PropertyAndValues[] => { - // 直接拿返回的 skus 属性逆向生成出 propertyList - const properties: PropertyAndValues[] = [] - // 只有是多规格才处理 - if (spu.specType) { - spu.skus?.forEach((sku) => { - sku.properties?.forEach(({ propertyId, propertyName, valueId, valueName }) => { - // 添加属性 - if (!properties?.some((item) => item.id === propertyId)) { - properties.push({ id: propertyId!, name: propertyName!, values: [] }) - } - // 添加属性值 - const index = properties?.findIndex((item) => item.id === propertyId) - if (!properties[index].values?.some((value) => value.id === valueId)) { - properties[index].values?.push({ id: valueId!, name: valueName! }) - } - }) - }) - } - return properties -} - // ====== end ====== const message = useMessage() // 消息弹窗 diff --git a/src/views/mall/product/spu/form/index.vue b/src/views/mall/product/spu/form/index.vue index db5b0445..0ba7a6d8 100644 --- a/src/views/mall/product/spu/form/index.vue +++ b/src/views/mall/product/spu/form/index.vue @@ -142,17 +142,6 @@ const submitForm = async () => { await unref(otherSettingsRef)?.validate() // 深拷贝一份, 这样最终 server 端不满足,不需要恢复, const deepCopyFormData = cloneDeep(unref(formData.value)) as ProductSpuApi.Spu - // 兜底处理 sku 空数据 - formData.value.skus!.forEach((sku) => { - // 因为是空数据这里判断一下商品条码是否为空就行 - if (sku.barCode === '') { - const index = deepCopyFormData.skus!.findIndex( - (item) => JSON.stringify(item.properties) === JSON.stringify(sku.properties) - ) - // 删除这条 sku - deepCopyFormData.skus!.splice(index, 1) - } - }) deepCopyFormData.skus!.forEach((item) => { // 给sku name赋值 item.name = deepCopyFormData.name @@ -189,7 +178,7 @@ const submitForm = async () => { /** 关闭按钮 */ const close = () => { delView(unref(currentRoute)) - push('/product/product-spu') + push({ name: 'ProductSpu' }) } /** 初始化 */ onMounted(async () => { diff --git a/src/views/mall/product/spu/index.vue b/src/views/mall/product/spu/index.vue index 9ea06cd5..2ed6d3ad 100644 --- a/src/views/mall/product/spu/index.vue +++ b/src/views/mall/product/spu/index.vue @@ -170,6 +170,14 @@ > 详情 + + 修改 + + diff --git a/src/views/mall/promotion/coupon/formatter.ts b/src/views/mall/promotion/coupon/formatter.ts new file mode 100644 index 00000000..2b0ba7c6 --- /dev/null +++ b/src/views/mall/promotion/coupon/formatter.ts @@ -0,0 +1,44 @@ +import { CouponTemplateValidityTypeEnum, PromotionDiscountTypeEnum } from '@/utils/constants' +import { formatDate } from '@/utils/formatTime' +import { CouponTemplateVO } from '@/api/mall/promotion/coupon/couponTemplate' +import { floatToFixed2 } from '@/utils' + +// 格式化【优惠金额/折扣】 +export const discountFormat = (row: CouponTemplateVO) => { + if (row.discountType === PromotionDiscountTypeEnum.PRICE.type) { + return `¥${floatToFixed2(row.discountPrice)}` + } + if (row.discountType === PromotionDiscountTypeEnum.PERCENT.type) { + return `${row.discountPrice}%` + } + return '未知【' + row.discountType + '】' +} + +// 格式化【领取上限】 +export const takeLimitCountFormat = (row: CouponTemplateVO) => { + if (row.takeLimitCount === -1) { + return '无领取限制' + } + return `${row.takeLimitCount} 张/人` +} + +// 格式化【有效期限】 +export const validityTypeFormat = (row: CouponTemplateVO) => { + if (row.validityType === CouponTemplateValidityTypeEnum.DATE.type) { + return `${formatDate(row.validStartTime)} 至 ${formatDate(row.validEndTime)}` + } + if (row.validityType === CouponTemplateValidityTypeEnum.TERM.type) { + return `领取后第 ${row.fixedStartTerm} - ${row.fixedEndTerm} 天内可用` + } + return '未知【' + row.validityType + '】' +} + +// 格式化【剩余数量】 +export const remainedCountFormat = (row: CouponTemplateVO) => { + return row.totalCount - row.takeCount +} + +// 格式化【最低消费】 +export const usePriceFormat = (row: CouponTemplateVO) => { + return `¥${floatToFixed2(row.usePrice)}` +} diff --git a/src/views/mall/promotion/coupon/index.vue b/src/views/mall/promotion/coupon/index.vue index acfccece..9f81edf2 100755 --- a/src/views/mall/promotion/coupon/index.vue +++ b/src/views/mall/promotion/coupon/index.vue @@ -122,7 +122,8 @@ const queryParams = reactive({ pageNo: 1, pageSize: 10, createTime: [], - status: undefined + status: undefined, + nickname: undefined }) const queryFormRef = ref() // 搜索的表单 diff --git a/src/views/mall/promotion/coupon/template/CouponTemplateForm.vue b/src/views/mall/promotion/coupon/template/CouponTemplateForm.vue index e0173c00..0c4238ac 100644 --- a/src/views/mall/promotion/coupon/template/CouponTemplateForm.vue +++ b/src/views/mall/promotion/coupon/template/CouponTemplateForm.vue @@ -10,7 +10,40 @@ - + + + + {{ dict.label }} + + + + +
+
+ + +
+
+ +
+
+
+ + + + @@ -43,7 +76,7 @@ @@ -68,7 +101,7 @@ @@ -84,7 +117,7 @@ @@ -94,7 +127,7 @@ @@ -119,7 +152,7 @@ @@ -133,7 +166,7 @@ @@ -141,49 +174,19 @@ 天有效 - - - - {{ dict.label }} - - - - - - - {{ item.name }} - - ¥{{ (item.minPrice / 100.0).toFixed(2) }} - - - - + + + diff --git a/src/views/mall/promotion/coupon/template/index.vue b/src/views/mall/promotion/coupon/template/index.vue index ee8dad46..ad0077ce 100755 --- a/src/views/mall/promotion/coupon/template/index.vue +++ b/src/views/mall/promotion/coupon/template/index.vue @@ -103,7 +103,7 @@ label="剩余数量" align="center" prop="totalCount" - :formatter="(row) => row.totalCount - row.takeCount" + :formatter="remainedCountFormat" /> import * as CouponTemplateApi from '@/api/mall/promotion/coupon/couponTemplate' -import { - CommonStatusEnum, - CouponTemplateValidityTypeEnum, - PromotionDiscountTypeEnum -} from '@/utils/constants' +import { CommonStatusEnum } from '@/utils/constants' import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' -import { dateFormatter, formatDate } from '@/utils/formatTime' +import { dateFormatter } from '@/utils/formatTime' import CouponTemplateForm from './CouponTemplateForm.vue' +import { + discountFormat, + remainedCountFormat, + takeLimitCountFormat, + validityTypeFormat +} from '@/views/mall/promotion/coupon/formatter' defineOptions({ name: 'PromotionCouponTemplate' }) @@ -193,6 +195,7 @@ const queryParams = reactive({ pageSize: 10, name: null, status: null, + discountType: null, type: null, createTime: [] }) @@ -258,36 +261,6 @@ const handleDelete = async (id: number) => { } catch {} } -// 格式化【优惠金额/折扣】 -const discountFormat = (row: any) => { - if (row.discountType === PromotionDiscountTypeEnum.PRICE.type) { - return `¥${(row.discountPrice / 100.0).toFixed(2)}` - } - if (row.discountType === PromotionDiscountTypeEnum.PERCENT.type) { - return `¥${(row.discountPrice / 100.0).toFixed(2)}` - } - return '未知【' + row.discountType + '】' -} - -// 格式化【领取上限】 -const takeLimitCountFormat = (row: any) => { - if (row.takeLimitCount === -1) { - return '无领取限制' - } - return `${row.takeLimitCount} 张/人` -} - -// 格式化【有效期限】 -const validityTypeFormat = (row: any) => { - if (row.validityType === CouponTemplateValidityTypeEnum.DATE.type) { - return `${formatDate(row.validStartTime)} 至 ${formatDate(row.validEndTime)}` - } - if (row.validityType === CouponTemplateValidityTypeEnum.TERM.type) { - return `领取后第 ${row.fixedStartTerm} - ${row.fixedEndTerm} 天内可用` - } - return '未知【' + row.validityType + '】' -} - /** 初始化 **/ onMounted(() => { getList() diff --git a/src/views/mall/trade/afterSale/detail/index.vue b/src/views/mall/trade/afterSale/detail/index.vue index 7802a805..190a4b33 100644 --- a/src/views/mall/trade/afterSale/detail/index.vue +++ b/src/views/mall/trade/afterSale/detail/index.vue @@ -122,8 +122,36 @@ - - + + + + + + 用户类型: + + 售后状态(之前): + + 售后状态(之后): + + 操作明细:{{ saleLog.content }} + + + + + @@ -138,12 +166,14 @@ import UpdateAuditReasonForm from '@/views/mall/trade/afterSale/form/AfterSaleDi import { createImageViewer } from '@/components/ImageViewer' import { isArray } from '@/utils/is' -defineOptions({ name: 'TradeOrderDetailForm' }) +defineOptions({ name: 'TradeAfterSaleDetail' }) +const { t } = useI18n() // 国际化 const message = useMessage() // 消息弹窗 const { params } = useRoute() // 查询参数 const formData = ref({ - order: {} + order: {}, + afterSaleLog: [] }) const updateAuditReasonFormRef = ref() // 拒绝售后表单 Ref @@ -154,44 +184,48 @@ const getDetail = async () => { formData.value = await AfterSaleApi.getAfterSale(id) } } -/** - * 同意售后 - */ + +/** 同意售后 */ const agree = () => { message.confirm('是否同意售后?').then(() => { AfterSaleApi.agree(formData.value.id) + message.success(t('common.success')) + getDetail() }) } -/** - * 拒绝售后 - */ + +/** 拒绝售后 */ const disagree = () => { updateAuditReasonFormRef.value?.open(formData.value) } -/** - * 确认收货 - */ + +/** 确认收货 */ const receive = () => { message.confirm('是否确认收货?').then(() => { AfterSaleApi.receive(formData.value.id) + message.success(t('common.success')) + getDetail() }) } -/** - * 拒绝收货 - */ + +/** 拒绝收货 */ const refuse = () => { message.confirm('是否拒绝收货?').then(() => { AfterSaleApi.refuse(formData.value.id) + message.success(t('common.success')) + getDetail() }) } -/** - * 确认退款 - */ + +/** 确认退款 */ const refund = () => { message.confirm('是否确认退款?').then(() => { AfterSaleApi.refund(formData.value.id) + message.success(t('common.success')) + getDetail() }) } + /** 图片预览 */ const imagePreview = (args) => { const urlList = [] @@ -206,6 +240,7 @@ const imagePreview = (args) => { urlList }) } + onMounted(async () => { await getDetail() }) diff --git a/src/views/mall/trade/order/detail/index.vue b/src/views/mall/trade/order/detail/index.vue index ef2d9958..a823fef5 100644 --- a/src/views/mall/trade/order/detail/index.vue +++ b/src/views/mall/trade/order/detail/index.vue @@ -2,32 +2,32 @@ - {{ orderInfo.no }} + {{ formData.no }} - + 秒杀活动 - + - {{ orderInfo.receiverName }} - {{ orderInfo.userRemark }} + {{ formData.receiverName }} + {{ formData.userRemark }} - + - {{ orderInfo.receiverMobile }} - {{ orderInfo.remark }} - {{ orderInfo.payOrderId }} + {{ formData.receiverMobile }} + {{ formData.remark }} + {{ formData.payOrderId }} - + - - + + - {{ orderInfo.receiverAreaName }} {{ orderInfo.receiverDetailAddress }} + {{ formData.receiverAreaName }} {{ formData.receiverDetailAddress }} - + + 调整价格 备注 @@ -59,7 +60,7 @@ - +