feat(sdy): 实现经销商订单结算功能

- 新增结算订单API接口
-优化订单编辑页面字段展示和计算逻辑
- 调整订单状态标签及删除条件限制- 增加订单导入弹窗组件- 修复重复结算问题并更新相关UI交互
This commit is contained in:
2025-10-01 19:25:51 +08:00
parent 320a1939b6
commit c7188ee8eb
5 changed files with 143 additions and 112 deletions

View File

@@ -118,3 +118,17 @@ export async function exportSdyDealerOrder(params?: ShopDealerOrderParam) {
message.error(error.message || '导出失败,请重试');
}
}
/**
* 结算订单
*/
export async function updateSdyDealerOrder(data: ShopDealerOrder) {
const res = await request.put<ApiResult<unknown>>(
'/sdy/sdy-dealer-order',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}

View File

@@ -62,6 +62,7 @@
</a-button>
<a-button
type="primary"
danger
@click="batchSettle"
class="ele-btn-icon"
>

View File

@@ -37,16 +37,23 @@
</a-col>
<a-col :span="12">
<a-form-item label="费率" name="rate">
<a-form-item label="结算电量" name="orderPrice">
{{ parseFloat(form.orderPrice || 0).toFixed(2) }}
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="收益比率" name="rate">
{{ form.rate }}
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="结算电量" name="orderPrice">
{{ parseFloat(form.orderPrice || 0).toFixed(2) }}
<a-form-item label="结算金额" name="payPrice">
{{ (form.orderPrice * form.rate * 1000).toFixed(2) }}
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="实发金额" name="payPrice">
{{ (form.orderPrice * form.rate * 1000).toFixed(2) }}
@@ -69,16 +76,17 @@
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="用户ID" name="firstUserId">
<a-input-number
:min="1"
placeholder="请输入一级分销商用户ID"
v-model:value="form.firstUserId"
style="width: 100%"
/>
{{ form.firstUserId }}
</a-form-item>
<a-form-item label="昵称" name="firstNickname">
{{ form.firstNickname }}
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="分销佣金" name="firstMoney">
<a-form-item label="收益比率" name="rate">
{{ '70%' }}
</a-form-item>
<a-form-item label="获取收益" name="firstMoney">
<a-input-number
:min="0"
:precision="2"
@@ -96,21 +104,22 @@
<!-- 二级分销商 -->
<div class="dealer-section">
<h4 class="dealer-title">
<a-tag color="orange">推收益</a-tag>
<a-tag color="orange">推收益</a-tag>
</h4>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="用户ID" name="secondUserId">
<a-input-number
:min="1"
placeholder="请输入二级分销商用户ID"
v-model:value="form.secondUserId"
style="width: 100%"
/>
{{ form.secondUserId }}
</a-form-item>
<a-form-item label="昵称" name="secondNickname">
{{ form.secondNickname }}
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="分销佣金" name="secondMoney">
<a-form-item label="收益比率" name="rate">
{{ '30%' }}
</a-form-item>
<a-form-item label="获取收益" name="secondMoney">
<a-input-number
:min="0"
:precision="2"
@@ -126,12 +135,7 @@
</div>
<a-form-item label="结算时间" name="settleTime" v-if="form.isSettled === 1">
<a-date-picker
v-model:value="form.settleTime"
show-time
placeholder="请选择结算时间"
style="width: 300px"
/>
{{ form.settleTime }}
</a-form-item>
</a-form>
</ele-modal>
@@ -140,22 +144,14 @@
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import dayjs from 'dayjs';
import { assignObject, uuid } from 'ele-admin-pro';
import { addShopDealerOrder, updateShopDealerOrder } from '@/api/shop/shopDealerOrder';
import { assignObject } from 'ele-admin-pro';
import { ShopDealerOrder } from '@/api/shop/shopDealerOrder/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
import {updateSdyDealerOrder} from "@/api/sdy/sdyDealerOrder";
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
@@ -175,7 +171,6 @@
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 表单数据
const form = reactive<ShopDealerOrder>({
@@ -210,79 +205,13 @@
// 表单验证规则
const rules = reactive({
orderId: [
userId: [
{
required: true,
message: '请输入订单ID',
message: '请选择用户ID',
trigger: 'blur'
}
],
firstUserId: [
{
validator: (rule: any, value: any) => {
if (form.firstMoney && !value) {
return Promise.reject('设置了一级佣金必须填写一级分销商用户ID');
}
return Promise.resolve();
},
trigger: 'blur'
}
],
firstMoney: [
{
validator: (rule: any, value: any) => {
if (form.firstUserId && !value) {
return Promise.reject('设置了一级分销商必须填写一级佣金');
}
return Promise.resolve();
},
trigger: 'blur'
}
],
secondUserId: [
{
validator: (rule: any, value: any) => {
if (form.secondMoney && !value) {
return Promise.reject('设置了二级佣金必须填写二级分销商用户ID');
}
return Promise.resolve();
},
trigger: 'blur'
}
],
secondMoney: [
{
validator: (rule: any, value: any) => {
if (form.secondUserId && !value) {
return Promise.reject('设置了二级分销商必须填写二级佣金');
}
return Promise.resolve();
},
trigger: 'blur'
}
],
thirdUserId: [
{
validator: (rule: any, value: any) => {
if (form.thirdMoney && !value) {
return Promise.reject('设置了三级佣金必须填写三级分销商用户ID');
}
return Promise.resolve();
},
trigger: 'blur'
}
],
thirdMoney: [
{
validator: (rule: any, value: any) => {
if (form.thirdUserId && !value) {
return Promise.reject('设置了三级分销商必须填写三级佣金');
}
return Promise.resolve();
},
trigger: 'blur'
}
]
});
@@ -294,6 +223,10 @@
if (!formRef.value) {
return;
}
if(form.isSettled == 1){
message.error('请勿重复结算');
return;
}
if(form.userId == 0){
message.error('未签约');
return;
@@ -303,10 +236,10 @@
.then(() => {
loading.value = true;
const formData = {
...form
...form,
isSettled: 1,
};
const saveOrUpdate = isUpdate.value ? updateShopDealerOrder : addShopDealerOrder;
saveOrUpdate(formData)
updateSdyDealerOrder(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
@@ -327,9 +260,8 @@
if (visible) {
if (props.data) {
assignObject(form, props.data);
// 处理时间字段
if (props.data.settleTime) {
form.settleTime = dayjs(props.data.settleTime);
if(props.data.orderPrice && props.data.rate){
form.firstMoney = (Number(props.data.orderPrice) * props.data.rate * 1000 * 0.5).toFixed(2)
}
isUpdate.value = true;
} else {

View File

@@ -66,7 +66,7 @@
<template v-if="column.key === 'isInvalid'">
<a-tag v-if="record.isInvalid === 0" color="success">已签约</a-tag>
<a-tag v-if="record.isInvalid === 1" color="error" @click="invalidateOrder(record)">未签约</a-tag>
<a-tag v-if="record.isInvalid === 1" color="error">未签约</a-tag>
</template>
<template v-if="column.key === 'isSettled'">
@@ -104,6 +104,7 @@
<!-- </a-popconfirm>-->
<!-- </template>-->
<a-popconfirm
v-if="record.isSettled === 0"
title="确定要删除吗?"
@confirm="remove(record)"
placement="topRight"
@@ -139,7 +140,7 @@ import {getPageTitle} from '@/utils/common';
import ShopDealerOrderEdit from './components/shopDealerOrderEdit.vue';
import {pageShopDealerOrder, removeShopDealerOrder, removeBatchShopDealerOrder} from '@/api/shop/shopDealerOrder';
import type {ShopDealerOrder, ShopDealerOrderParam} from '@/api/shop/shopDealerOrder/model';
import {exportSdyDealerOrder} from "@/api/sdy/sdyDealerOrder";
import {exportSdyDealerOrder, updateSdyDealerOrder} from "@/api/sdy/sdyDealerOrder";
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
@@ -270,7 +271,7 @@ const settleOrder = (row: ShopDealerOrder) => {
Modal.confirm({
title: '确认结算',
content: `确定要结算此订单的佣金吗?总佣金金额:¥${totalCommission}`,
content: `确定要结算此订单吗?总佣金金额:¥${totalCommission}`,
icon: createVNode(DollarOutlined),
okText: '确认结算',
okType: 'primary',
@@ -278,6 +279,10 @@ const settleOrder = (row: ShopDealerOrder) => {
onOk: () => {
const hide = message.loading('正在结算...', 0);
// 这里调用结算API
updateSdyDealerOrder({
...row,
isSettled: 1
})
setTimeout(() => {
hide();
message.success('结算成功');

View File

@@ -0,0 +1,79 @@
<!-- 经销商订单导入弹窗 -->
<template>
<ele-modal
:width="520"
:footer="null"
title="导入分销订单"
:visible="visible"
@update:visible="updateVisible"
>
<a-spin :spinning="loading">
<a-upload-dragger
accept=".xls,.xlsx"
:show-upload-list="false"
:customRequest="doUpload"
style="padding: 24px 0; margin-bottom: 16px"
>
<p class="ant-upload-drag-icon">
<cloud-upload-outlined />
</p>
<p class="ant-upload-hint">将文件拖到此处或点击上传</p>
</a-upload-dragger>
</a-spin>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { message } from 'ant-design-vue/es';
import { CloudUploadOutlined } from '@ant-design/icons-vue';
import { importShopDealerOrder } from '@/api/shop/shopDealerOrder';
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
defineProps<{
// 是否打开弹窗
visible: boolean;
}>();
// 导入请求状态
const loading = ref(false);
/* 上传 */
const doUpload = ({ file }) => {
if (
![
'application/vnd.ms-excel',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
].includes(file.type)
) {
message.error('只能选择 excel 文件');
return false;
}
if (file.size / 1024 / 1024 > 10) {
message.error('大小不能超过 10MB');
return false;
}
loading.value = true;
importShopDealerOrder(file)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
return false;
};
/* 更新 visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
</script>