✨ 完善毛利分析筛选与导出日志
This commit is contained in:
+114
-9
@@ -1,23 +1,31 @@
|
||||
package com.bms.web.controller.report;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
// 提成功能暂停使用:import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.bms.common.annotation.Log;
|
||||
import com.bms.common.config.BmsConfig;
|
||||
import com.bms.common.core.controller.BaseController;
|
||||
import com.bms.common.core.domain.AjaxResult;
|
||||
import com.bms.common.core.page.TableDataInfo;
|
||||
import com.bms.common.enums.BusinessType;
|
||||
import com.bms.common.exception.ServiceException;
|
||||
import com.bms.common.utils.file.FileUtils;
|
||||
import com.bms.common.utils.poi.ExcelUtil;
|
||||
import com.bms.price.domain.PrcProfitCommissionRate;
|
||||
// 提成功能暂停使用:import com.bms.price.domain.PrcProfitCommissionRate;
|
||||
import com.bms.price.domain.PrcProfitReportExport;
|
||||
import com.bms.price.domain.vo.PrcProfitReportOrderRow;
|
||||
import com.bms.price.domain.vo.PrcProfitReportProductRow;
|
||||
import com.bms.price.domain.vo.PrcProfitReportQuery;
|
||||
@@ -39,6 +47,7 @@ public class PrcProfitReportController extends BaseController
|
||||
return success(profitReportService.selectSummary(query));
|
||||
}
|
||||
|
||||
/* 提成比例查询、维护、删除接口暂停使用,保留代码便于恢复。
|
||||
@PreAuthorize("@ss.hasPermi('report:profit:commission:list')")
|
||||
@GetMapping("/commission-rates")
|
||||
public AjaxResult commissionRates()
|
||||
@@ -62,6 +71,7 @@ public class PrcProfitReportController extends BaseController
|
||||
{
|
||||
return toAjax(profitReportService.deleteCommissionRate(rateId));
|
||||
}
|
||||
*/
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('report:profit:list')")
|
||||
@GetMapping("/orders")
|
||||
@@ -84,20 +94,115 @@ public class PrcProfitReportController extends BaseController
|
||||
@Log(title = "毛利报表-订单维度", businessType = BusinessType.EXPORT)
|
||||
@PreAuthorize("@ss.hasPermi('report:profit:export')")
|
||||
@PostMapping("/orders/export")
|
||||
public void exportOrders(HttpServletResponse response, PrcProfitReportQuery query)
|
||||
public AjaxResult exportOrders(PrcProfitReportQuery query)
|
||||
{
|
||||
PrcProfitReportExport export = beginExport("ORDER", "订单维度毛利分析");
|
||||
try
|
||||
{
|
||||
List<PrcProfitReportOrderRow> rows = profitReportService.selectOrderRows(query);
|
||||
new ExcelUtil<PrcProfitReportOrderRow>(PrcProfitReportOrderRow.class)
|
||||
.exportExcel(response, rows, "订单毛利报表");
|
||||
AjaxResult file = new ExcelUtil<PrcProfitReportOrderRow>(PrcProfitReportOrderRow.class)
|
||||
.exportExcel(rows, "订单毛利报表");
|
||||
return finishExport(export, rows.size(), file);
|
||||
}
|
||||
catch (RuntimeException e)
|
||||
{
|
||||
failExport(export, e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Log(title = "毛利报表-产品维度", businessType = BusinessType.EXPORT)
|
||||
@PreAuthorize("@ss.hasPermi('report:profit:export')")
|
||||
@PostMapping("/products/export")
|
||||
public void exportProducts(HttpServletResponse response, PrcProfitReportQuery query)
|
||||
public AjaxResult exportProducts(PrcProfitReportQuery query)
|
||||
{
|
||||
PrcProfitReportExport export = beginExport("PRODUCT", "产品维度毛利分析");
|
||||
try
|
||||
{
|
||||
List<PrcProfitReportProductRow> rows = profitReportService.selectProductRows(query);
|
||||
new ExcelUtil<PrcProfitReportProductRow>(PrcProfitReportProductRow.class)
|
||||
.exportExcel(response, rows, "产品毛利报表");
|
||||
AjaxResult file = new ExcelUtil<PrcProfitReportProductRow>(PrcProfitReportProductRow.class)
|
||||
.exportExcel(rows, "产品毛利报表");
|
||||
return finishExport(export, rows.size(), file);
|
||||
}
|
||||
catch (RuntimeException e)
|
||||
{
|
||||
failExport(export, e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('report:profit:export')")
|
||||
@GetMapping("/exports")
|
||||
public TableDataInfo exports()
|
||||
{
|
||||
startPage();
|
||||
return getDataTable(profitReportService.selectExports(getUsername()));
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('report:profit:export')")
|
||||
@GetMapping("/exports/{exportId}/download")
|
||||
public void downloadExport(@PathVariable Long exportId, HttpServletResponse response) throws Exception
|
||||
{
|
||||
PrcProfitReportExport export = profitReportService.selectExport(exportId, getUsername());
|
||||
if (export == null || !"SUCCESS".equals(export.getExportStatus())
|
||||
|| export.getStorageKey() == null || !FileUtils.checkAllowDownload(export.getStorageKey()))
|
||||
{
|
||||
throw new ServiceException("导出文件不存在或尚未生成成功");
|
||||
}
|
||||
|
||||
Path downloadRoot = Paths.get(BmsConfig.getDownloadPath()).toAbsolutePath().normalize();
|
||||
Path filePath = downloadRoot.resolve(export.getStorageKey()).normalize();
|
||||
if (!filePath.startsWith(downloadRoot) || !Files.isRegularFile(filePath))
|
||||
{
|
||||
throw new ServiceException("导出文件不存在或路径非法");
|
||||
}
|
||||
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||
FileUtils.setAttachmentResponseHeader(response, export.getFileName());
|
||||
FileUtils.writeBytes(filePath.toString(), response.getOutputStream());
|
||||
}
|
||||
|
||||
private PrcProfitReportExport beginExport(String dimension, String filePrefix)
|
||||
{
|
||||
PrcProfitReportExport export = new PrcProfitReportExport();
|
||||
export.setDimension(dimension);
|
||||
export.setFileName(filePrefix + "_" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + ".xlsx");
|
||||
export.setExportStatus("PROCESSING");
|
||||
export.setExportBy(getUsername());
|
||||
if (profitReportService.createExport(export) != 1)
|
||||
{
|
||||
throw new ServiceException("创建导出日志失败");
|
||||
}
|
||||
return export;
|
||||
}
|
||||
|
||||
private AjaxResult finishExport(PrcProfitReportExport export, int rowCount, AjaxResult file)
|
||||
{
|
||||
Object storageKey = file.get("msg");
|
||||
if (storageKey == null || String.valueOf(storageKey).isBlank())
|
||||
{
|
||||
throw new ServiceException("导出文件生成失败");
|
||||
}
|
||||
export.setStorageKey(String.valueOf(storageKey));
|
||||
export.setRowCount(rowCount);
|
||||
export.setExportStatus("SUCCESS");
|
||||
if (profitReportService.completeExport(export) != 1)
|
||||
{
|
||||
throw new ServiceException("保存导出日志失败");
|
||||
}
|
||||
return success(export);
|
||||
}
|
||||
|
||||
private void failExport(PrcProfitReportExport export, RuntimeException e)
|
||||
{
|
||||
String message = e.getMessage();
|
||||
if (message == null || message.isBlank())
|
||||
{
|
||||
message = "导出失败";
|
||||
}
|
||||
if (message.length() > 500)
|
||||
{
|
||||
message = message.substring(0, 500);
|
||||
}
|
||||
profitReportService.failExport(export.getExportId(), message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.bms.price.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import lombok.Data;
|
||||
|
||||
/** 毛利报表导出日志。 */
|
||||
@Data
|
||||
public class PrcProfitReportExport implements Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long exportId;
|
||||
/** PRODUCT 产品维度,ORDER 订单维度。 */
|
||||
private String dimension;
|
||||
private String fileName;
|
||||
/** 服务器下载目录下的相对文件名,不返回给前端。 */
|
||||
@JsonIgnore
|
||||
private String storageKey;
|
||||
private Integer rowCount;
|
||||
/** PROCESSING 生成中,SUCCESS 成功,FAILED 失败。 */
|
||||
private String exportStatus;
|
||||
private String exportBy;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date exportTime;
|
||||
private String remark;
|
||||
}
|
||||
+3
-1
@@ -50,10 +50,12 @@ public class PrcProfitReportOrderRow implements Serializable
|
||||
private BigDecimal salesGrossProfit;
|
||||
@Excel(name = "销售毛利率(%)", scale = 4, width = 18)
|
||||
private BigDecimal salesGrossMarginRate;
|
||||
/* 提成字段及 Excel 导出列暂停使用。
|
||||
@Excel(name = "提成比例(%)", scale = 4, width = 16)
|
||||
private BigDecimal commissionRate;
|
||||
@Excel(name = "提成金额", scale = 4, width = 16)
|
||||
private BigDecimal commissionAmount;
|
||||
@Excel(name = "应收状态", width = 14)
|
||||
*/
|
||||
@Excel(name = "应收状态", readConverterExp = "UNBILLED=未出账,PARTIAL=部分出账,BILLED=已出账", width = 14)
|
||||
private String arBillStatus;
|
||||
}
|
||||
|
||||
+2
@@ -37,10 +37,12 @@ public class PrcProfitReportProductRow implements Serializable
|
||||
private BigDecimal salesGrossProfit;
|
||||
@Excel(name = "销售毛利率(%)", scale = 4, width = 18)
|
||||
private BigDecimal salesGrossMarginRate;
|
||||
/* 提成字段及 Excel 导出列暂停使用。
|
||||
@Excel(name = "提成金额", scale = 4, width = 16)
|
||||
private BigDecimal commissionAmount;
|
||||
@Excel(name = "未计算提成订单数", width = 20)
|
||||
private Long commissionMissingOrderCount;
|
||||
*/
|
||||
@Excel(name = "产品价或价格缺失订单数", width = 22)
|
||||
private Long incompleteOrderCount;
|
||||
}
|
||||
|
||||
@@ -31,8 +31,10 @@ public class PrcProfitReportQuery extends BaseEntity
|
||||
private String productCode;
|
||||
private String countryCode;
|
||||
private String currency;
|
||||
/** 订单维度应收状态筛选:UNBILLED、PARTIAL、BILLED。 */
|
||||
private String arBillStatus;
|
||||
/** 是否按产品维度分组值下钻订单明细,允许分组字段为空。 */
|
||||
private Boolean productDrilldown;
|
||||
/** 订单明细弹窗的筛选类型:ALL、COMMISSION_MISSING、INCOMPLETE。 */
|
||||
/** 订单明细弹窗的筛选类型:ALL、INCOMPLETE;COMMISSION_MISSING 暂停使用。 */
|
||||
private String detailType;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ public class PrcProfitReportSummary implements Serializable
|
||||
private BigDecimal salesAmount;
|
||||
private BigDecimal salesGrossProfit;
|
||||
private BigDecimal salesGrossMarginRate;
|
||||
/* 提成汇总指标暂停使用。
|
||||
private BigDecimal commissionAmount;
|
||||
private Long commissionMissingOrderCount;
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.bms.price.mapper;
|
||||
|
||||
import java.util.List;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import com.bms.price.domain.PrcProfitReportExport;
|
||||
import com.bms.price.domain.vo.PrcProfitReportOrderRow;
|
||||
import com.bms.price.domain.vo.PrcProfitReportProductRow;
|
||||
import com.bms.price.domain.vo.PrcProfitReportQuery;
|
||||
@@ -14,4 +16,15 @@ public interface PrcProfitReportMapper
|
||||
List<PrcProfitReportProductRow> selectProductRows(PrcProfitReportQuery query);
|
||||
|
||||
List<PrcProfitReportSummary> selectSummary(PrcProfitReportQuery query);
|
||||
|
||||
int insertExport(PrcProfitReportExport export);
|
||||
|
||||
int markExportSuccess(PrcProfitReportExport export);
|
||||
|
||||
int markExportFailed(@Param("exportId") Long exportId, @Param("remark") String remark);
|
||||
|
||||
List<PrcProfitReportExport> selectExportsByUser(String exportBy);
|
||||
|
||||
PrcProfitReportExport selectExportByIdAndUser(@Param("exportId") Long exportId,
|
||||
@Param("exportBy") String exportBy);
|
||||
}
|
||||
|
||||
+14
-1
@@ -1,7 +1,8 @@
|
||||
package com.bms.price.service;
|
||||
|
||||
import java.util.List;
|
||||
import com.bms.price.domain.PrcProfitCommissionRate;
|
||||
// 提成功能暂停使用:import com.bms.price.domain.PrcProfitCommissionRate;
|
||||
import com.bms.price.domain.PrcProfitReportExport;
|
||||
import com.bms.price.domain.vo.PrcProfitReportOrderRow;
|
||||
import com.bms.price.domain.vo.PrcProfitReportProductRow;
|
||||
import com.bms.price.domain.vo.PrcProfitReportQuery;
|
||||
@@ -16,9 +17,21 @@ public interface IPrcProfitReportService
|
||||
|
||||
List<PrcProfitReportSummary> selectSummary(PrcProfitReportQuery query);
|
||||
|
||||
int createExport(PrcProfitReportExport export);
|
||||
|
||||
int completeExport(PrcProfitReportExport export);
|
||||
|
||||
int failExport(Long exportId, String remark);
|
||||
|
||||
List<PrcProfitReportExport> selectExports(String exportBy);
|
||||
|
||||
PrcProfitReportExport selectExport(Long exportId, String exportBy);
|
||||
|
||||
/* 提成比例维护暂停使用。
|
||||
List<PrcProfitCommissionRate> selectCommissionRates();
|
||||
|
||||
void saveCommissionRate(PrcProfitCommissionRate rate);
|
||||
|
||||
int deleteCommissionRate(Long rateId);
|
||||
*/
|
||||
}
|
||||
|
||||
+44
-5
@@ -3,15 +3,16 @@ package com.bms.price.service.impl;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.math.BigDecimal;
|
||||
// 提成功能暂停使用:import java.math.BigDecimal;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
// 提成功能暂停使用:import org.springframework.transaction.annotation.Transactional;
|
||||
import com.bms.common.annotation.DataScope;
|
||||
import com.bms.common.exception.ServiceException;
|
||||
import com.bms.common.utils.SecurityUtils;
|
||||
import com.bms.price.domain.PrcProfitCommissionRate;
|
||||
import com.bms.price.mapper.PrcProfitCommissionRateMapper;
|
||||
// 提成功能暂停使用:import com.bms.common.utils.SecurityUtils;
|
||||
// 提成功能暂停使用:import com.bms.price.domain.PrcProfitCommissionRate;
|
||||
// 提成功能暂停使用:import com.bms.price.mapper.PrcProfitCommissionRateMapper;
|
||||
import com.bms.price.domain.PrcProfitReportExport;
|
||||
import com.bms.price.domain.vo.PrcProfitReportOrderRow;
|
||||
import com.bms.price.domain.vo.PrcProfitReportProductRow;
|
||||
import com.bms.price.domain.vo.PrcProfitReportQuery;
|
||||
@@ -28,8 +29,10 @@ public class PrcProfitReportServiceImpl implements IPrcProfitReportService
|
||||
@Autowired
|
||||
private PrcProfitReportMapper profitReportMapper;
|
||||
|
||||
/* 提成配置依赖暂停使用。
|
||||
@Autowired
|
||||
private PrcProfitCommissionRateMapper commissionRateMapper;
|
||||
*/
|
||||
|
||||
@Override
|
||||
@DataScope(deptAlias = "su", deptField = "dept_id", userAlias = "su", userField = "user_id", permission = "report:profit:list")
|
||||
@@ -55,6 +58,36 @@ public class PrcProfitReportServiceImpl implements IPrcProfitReportService
|
||||
return profitReportMapper.selectSummary(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int createExport(PrcProfitReportExport export)
|
||||
{
|
||||
return profitReportMapper.insertExport(export);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int completeExport(PrcProfitReportExport export)
|
||||
{
|
||||
return profitReportMapper.markExportSuccess(export);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int failExport(Long exportId, String remark)
|
||||
{
|
||||
return profitReportMapper.markExportFailed(exportId, remark);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PrcProfitReportExport> selectExports(String exportBy)
|
||||
{
|
||||
return profitReportMapper.selectExportsByUser(exportBy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrcProfitReportExport selectExport(Long exportId, String exportBy)
|
||||
{
|
||||
return profitReportMapper.selectExportByIdAndUser(exportId, exportBy);
|
||||
}
|
||||
|
||||
/** 将报表的多行输入拆分为去重后的查询条件,支持换行、空格、逗号和分号分隔。 */
|
||||
private void normalizeMultiValueFilters(PrcProfitReportQuery query)
|
||||
{
|
||||
@@ -62,6 +95,10 @@ public class PrcProfitReportServiceImpl implements IPrcProfitReportService
|
||||
{
|
||||
return;
|
||||
}
|
||||
if ("COMMISSION_MISSING".equals(query.getDetailType()))
|
||||
{
|
||||
throw new ServiceException("提成功能已暂停使用");
|
||||
}
|
||||
query.setOrderNos(splitFilterValues(query.getOrderNo(), "订单号"));
|
||||
query.setCustomerCodes(splitFilterValues(query.getCustomerCode(), "客户代码"));
|
||||
query.setCustomerNames(splitFilterValues(query.getCustomerName(), "客户名称"));
|
||||
@@ -88,6 +125,7 @@ public class PrcProfitReportServiceImpl implements IPrcProfitReportService
|
||||
return new ArrayList<>(values);
|
||||
}
|
||||
|
||||
/* 提成比例查询、保存、删除暂停使用,保留原逻辑便于恢复。
|
||||
@Override
|
||||
public List<PrcProfitCommissionRate> selectCommissionRates()
|
||||
{
|
||||
@@ -136,4 +174,5 @@ public class PrcProfitReportServiceImpl implements IPrcProfitReportService
|
||||
}
|
||||
return commissionRateMapper.deleteById(rateId);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -4,6 +4,56 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.bms.price.mapper.PrcProfitReportMapper">
|
||||
|
||||
<resultMap type="PrcProfitReportExport" id="PrcProfitReportExportResult">
|
||||
<id property="exportId" column="export_id"/>
|
||||
<result property="dimension" column="dimension"/>
|
||||
<result property="fileName" column="file_name"/>
|
||||
<result property="storageKey" column="storage_key"/>
|
||||
<result property="rowCount" column="row_count"/>
|
||||
<result property="exportStatus" column="export_status"/>
|
||||
<result property="exportBy" column="export_by"/>
|
||||
<result property="exportTime" column="export_time"/>
|
||||
<result property="remark" column="remark"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="profitReportExportColumns">
|
||||
select export_id, dimension, file_name, storage_key, row_count,
|
||||
export_status, export_by, export_time, remark
|
||||
from prc_profit_report_export
|
||||
</sql>
|
||||
|
||||
<insert id="insertExport" parameterType="PrcProfitReportExport" useGeneratedKeys="true" keyProperty="exportId">
|
||||
insert into prc_profit_report_export (
|
||||
dimension, file_name, storage_key, row_count, export_status, export_by, export_time, remark
|
||||
) values (
|
||||
#{dimension}, #{fileName}, #{storageKey}, #{rowCount}, #{exportStatus}, #{exportBy}, sysdate(), #{remark}
|
||||
)
|
||||
</insert>
|
||||
|
||||
<update id="markExportSuccess" parameterType="PrcProfitReportExport">
|
||||
update prc_profit_report_export
|
||||
set file_name = #{fileName}, storage_key = #{storageKey}, row_count = #{rowCount},
|
||||
export_status = 'SUCCESS', remark = null
|
||||
where export_id = #{exportId} and export_status = 'PROCESSING'
|
||||
</update>
|
||||
|
||||
<update id="markExportFailed">
|
||||
update prc_profit_report_export
|
||||
set export_status = 'FAILED', remark = #{remark}
|
||||
where export_id = #{exportId} and export_status = 'PROCESSING'
|
||||
</update>
|
||||
|
||||
<select id="selectExportsByUser" resultMap="PrcProfitReportExportResult">
|
||||
<include refid="profitReportExportColumns"/>
|
||||
where export_by = #{exportBy}
|
||||
order by export_time desc, export_id desc
|
||||
</select>
|
||||
|
||||
<select id="selectExportByIdAndUser" resultMap="PrcProfitReportExportResult">
|
||||
<include refid="profitReportExportColumns"/>
|
||||
where export_id = #{exportId} and export_by = #{exportBy}
|
||||
</select>
|
||||
|
||||
<resultMap type="PrcProfitReportOrderRow" id="PrcProfitReportOrderResult">
|
||||
<result property="orderNo" column="order_no"/>
|
||||
<result property="customerCode" column="customer_code"/>
|
||||
@@ -23,8 +73,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<result property="salesAmount" column="sales_amount"/>
|
||||
<result property="salesGrossProfit" column="sales_gross_profit"/>
|
||||
<result property="salesGrossMarginRate" column="sales_gross_margin_rate"/>
|
||||
<!-- 提成结果字段暂停使用。
|
||||
<result property="commissionRate" column="commission_rate"/>
|
||||
<result property="commissionAmount" column="commission_amount"/>
|
||||
-->
|
||||
<result property="arBillStatus" column="ar_bill_status"/>
|
||||
</resultMap>
|
||||
|
||||
@@ -42,8 +94,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<result property="salesAmount" column="sales_amount"/>
|
||||
<result property="salesGrossProfit" column="sales_gross_profit"/>
|
||||
<result property="salesGrossMarginRate" column="sales_gross_margin_rate"/>
|
||||
<!-- 提成结果字段暂停使用。
|
||||
<result property="commissionAmount" column="commission_amount"/>
|
||||
<result property="commissionMissingOrderCount" column="commission_missing_order_count"/>
|
||||
-->
|
||||
<result property="incompleteOrderCount" column="incomplete_order_count"/>
|
||||
</resultMap>
|
||||
|
||||
@@ -58,16 +112,22 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<result property="salesAmount" column="sales_amount"/>
|
||||
<result property="salesGrossProfit" column="sales_gross_profit"/>
|
||||
<result property="salesGrossMarginRate" column="sales_gross_margin_rate"/>
|
||||
<!-- 提成汇总字段暂停使用。
|
||||
<result property="commissionAmount" column="commission_amount"/>
|
||||
<result property="commissionMissingOrderCount" column="commission_missing_order_count"/>
|
||||
-->
|
||||
</resultMap>
|
||||
|
||||
<sql id="profitReportFromAndWhere">
|
||||
from prc_income_bill i
|
||||
inner join prc_order_bill p on p.bill_id = i.bill_id
|
||||
<!-- 提成表关联暂停使用,毛利报表不再依赖提成配置。
|
||||
left join prc_profit_commission_rate cr
|
||||
on cr.belong_saler_code = i.belong_saler_code and cr.status = '0'
|
||||
-->
|
||||
<where>
|
||||
<!-- 不将未匹配产品、国家或重量段的计费失败订单纳入毛利报表;保留历史空值(按成功处理)。 -->
|
||||
and (p.billing_fail_status is null or p.billing_fail_status not in (1, 2, 3))
|
||||
<if test="beginBizDate != null">
|
||||
and p.biz_date >= #{beginBizDate}
|
||||
</if>
|
||||
@@ -134,9 +194,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</otherwise>
|
||||
</choose>
|
||||
<choose>
|
||||
<!-- 提成未计算订单下钻暂停使用。
|
||||
<when test="detailType == 'COMMISSION_MISSING'">
|
||||
and (cr.commission_rate is null or i.product_amount is null or i.sales_amount is null)
|
||||
</when>
|
||||
-->
|
||||
<when test="detailType == 'INCOMPLETE'">
|
||||
and (i.product_amount is null or i.redline_amount is null or i.sales_amount is null)
|
||||
</when>
|
||||
@@ -161,21 +223,24 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</where>
|
||||
</sql>
|
||||
|
||||
<!-- 红线毛利 = 产品价 - 红线价;红线毛利率 = 红线毛利 / 红线价 * 100%。汇总先逐单计算再求和。 -->
|
||||
<sql id="profitExpressions">
|
||||
i.product_amount as cost_amount,
|
||||
i.redline_amount,
|
||||
case when i.product_amount is not null and i.redline_amount is not null
|
||||
then i.redline_amount - i.product_amount else null end as redline_gross_profit,
|
||||
then i.product_amount - i.redline_amount else null end as redline_gross_profit,
|
||||
case when i.product_amount is not null and i.redline_amount is not null and i.redline_amount != 0
|
||||
then round((i.redline_amount - i.product_amount) * 100 / i.redline_amount, 4) else null end as redline_gross_margin_rate,
|
||||
then round((i.product_amount - i.redline_amount) * 100 / i.redline_amount, 4) else null end as redline_gross_margin_rate,
|
||||
i.sales_amount,
|
||||
case when i.product_amount is not null and i.sales_amount is not null
|
||||
then i.sales_amount - i.product_amount else null end as sales_gross_profit,
|
||||
case when i.product_amount is not null and i.sales_amount is not null and i.sales_amount != 0
|
||||
then round((i.sales_amount - i.product_amount) * 100 / i.sales_amount, 4) else null end as sales_gross_margin_rate,
|
||||
cr.commission_rate,
|
||||
then round((i.sales_amount - i.product_amount) * 100 / i.sales_amount, 4) else null end as sales_gross_margin_rate
|
||||
<!-- 提成比例与金额计算暂停使用;恢复时包含前置逗号。
|
||||
, cr.commission_rate,
|
||||
case when cr.commission_rate is not null and i.product_amount is not null and i.sales_amount is not null
|
||||
then round((i.sales_amount - i.product_amount) * cr.commission_rate / 100, 4) else null end as commission_amount
|
||||
-->
|
||||
</sql>
|
||||
|
||||
<select id="selectOrderRows" resultMap="PrcProfitReportOrderResult">
|
||||
@@ -186,6 +251,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<include refid="profitExpressions"/>,
|
||||
p.ar_bill_status
|
||||
<include refid="profitReportFromAndWhere"/>
|
||||
<if test="arBillStatus != null and arBillStatus != '' and productDrilldown != true">
|
||||
and p.ar_bill_status = #{arBillStatus}
|
||||
</if>
|
||||
order by p.biz_date desc, p.bill_id desc
|
||||
</select>
|
||||
|
||||
@@ -195,7 +263,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
sum(i.product_amount) as cost_amount,
|
||||
sum(i.redline_amount) as redline_amount,
|
||||
sum(case when i.product_amount is not null and i.redline_amount is not null
|
||||
then i.redline_amount - i.product_amount else null end) as redline_gross_profit,
|
||||
then i.product_amount - i.redline_amount else null end) as redline_gross_profit,
|
||||
case when sum(case when i.product_amount is not null and i.redline_amount is not null
|
||||
then i.redline_amount else null end) is null
|
||||
or sum(case when i.product_amount is not null and i.redline_amount is not null
|
||||
@@ -203,7 +271,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
then null
|
||||
else round(
|
||||
sum(case when i.product_amount is not null and i.redline_amount is not null
|
||||
then i.redline_amount - i.product_amount else null end) * 100 /
|
||||
then i.product_amount - i.redline_amount else null end) * 100 /
|
||||
sum(case when i.product_amount is not null and i.redline_amount is not null
|
||||
then i.redline_amount else null end), 4)
|
||||
end as redline_gross_margin_rate,
|
||||
@@ -221,10 +289,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
sum(case when i.product_amount is not null and i.sales_amount is not null
|
||||
then i.sales_amount else null end), 4)
|
||||
end as sales_gross_margin_rate,
|
||||
<!-- 提成金额与未计算订单数暂停使用。
|
||||
sum(case when cr.commission_rate is not null and i.product_amount is not null and i.sales_amount is not null
|
||||
then (i.sales_amount - i.product_amount) * cr.commission_rate / 100 else null end) as commission_amount,
|
||||
sum(case when cr.commission_rate is null or i.product_amount is null or i.sales_amount is null
|
||||
then 1 else 0 end) as commission_missing_order_count,
|
||||
-->
|
||||
sum(case when i.product_amount is null or i.redline_amount is null or i.sales_amount is null
|
||||
then 1 else 0 end) as incomplete_order_count
|
||||
<include refid="profitReportFromAndWhere"/>
|
||||
@@ -239,7 +309,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
sum(i.product_amount) as cost_amount,
|
||||
sum(i.redline_amount) as redline_amount,
|
||||
sum(case when i.product_amount is not null and i.redline_amount is not null
|
||||
then i.redline_amount - i.product_amount else null end) as redline_gross_profit,
|
||||
then i.product_amount - i.redline_amount else null end) as redline_gross_profit,
|
||||
case when sum(case when i.product_amount is not null and i.redline_amount is not null
|
||||
then i.redline_amount else null end) is null
|
||||
or sum(case when i.product_amount is not null and i.redline_amount is not null
|
||||
@@ -247,7 +317,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
then null
|
||||
else round(
|
||||
sum(case when i.product_amount is not null and i.redline_amount is not null
|
||||
then i.redline_amount - i.product_amount else null end) * 100 /
|
||||
then i.product_amount - i.redline_amount else null end) * 100 /
|
||||
sum(case when i.product_amount is not null and i.redline_amount is not null
|
||||
then i.redline_amount else null end), 4)
|
||||
end as redline_gross_margin_rate,
|
||||
@@ -264,12 +334,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
then i.sales_amount - i.product_amount else null end) * 100 /
|
||||
sum(case when i.product_amount is not null and i.sales_amount is not null
|
||||
then i.sales_amount else null end), 4)
|
||||
end as sales_gross_margin_rate,
|
||||
sum(case when cr.commission_rate is not null and i.product_amount is not null and i.sales_amount is not null
|
||||
end as sales_gross_margin_rate
|
||||
<!-- 提成汇总计算暂停使用;恢复时包含前置逗号。
|
||||
, sum(case when cr.commission_rate is not null and i.product_amount is not null and i.sales_amount is not null
|
||||
then (i.sales_amount - i.product_amount) * cr.commission_rate / 100 else null end) as commission_amount,
|
||||
sum(case when cr.commission_rate is null or i.product_amount is null or i.sales_amount is null
|
||||
then 1 else 0 end) as commission_missing_order_count
|
||||
-->
|
||||
<include refid="profitReportFromAndWhere"/>
|
||||
<if test="arBillStatus != null and arBillStatus != ''">
|
||||
and p.ar_bill_status = #{arBillStatus}
|
||||
</if>
|
||||
group by i.currency
|
||||
order by i.currency
|
||||
</select>
|
||||
|
||||
@@ -2326,3 +2326,19 @@ CREATE TABLE `test` (
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
|
||||
-- 毛利分析导出日志;已有环境请执行 sql/price/prc_profit_report_export_log.sql。
|
||||
CREATE TABLE IF NOT EXISTS `prc_profit_report_export` (
|
||||
`export_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '毛利报表导出ID',
|
||||
`dimension` varchar(16) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'PRODUCT产品维度,ORDER订单维度',
|
||||
`file_name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '下载文件名',
|
||||
`storage_key` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '下载目录下的文件Key',
|
||||
`row_count` int(11) DEFAULT NULL COMMENT '导出记录数',
|
||||
`export_status` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'PROCESSING生成中,SUCCESS成功,FAILED失败',
|
||||
`export_by` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '导出人',
|
||||
`export_time` datetime NOT NULL COMMENT '导出时间',
|
||||
`remark` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '失败原因',
|
||||
PRIMARY KEY (`export_id`),
|
||||
KEY `idx_profit_report_export_user_time` (`export_by`, `export_time`),
|
||||
KEY `idx_profit_report_export_status` (`export_status`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='毛利报表导出日志';
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
-- 毛利分析产品、订单维度导出日志及历史文件索引。
|
||||
CREATE TABLE IF NOT EXISTS `prc_profit_report_export` (
|
||||
`export_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '毛利报表导出ID',
|
||||
`dimension` varchar(16) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'PRODUCT产品维度,ORDER订单维度',
|
||||
`file_name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '下载文件名',
|
||||
`storage_key` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '下载目录下的文件Key',
|
||||
`row_count` int(11) DEFAULT NULL COMMENT '导出记录数',
|
||||
`export_status` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'PROCESSING生成中,SUCCESS成功,FAILED失败',
|
||||
`export_by` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '导出人',
|
||||
`export_time` datetime NOT NULL COMMENT '导出时间',
|
||||
`remark` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '失败原因',
|
||||
PRIMARY KEY (`export_id`),
|
||||
KEY `idx_profit_report_export_user_time` (`export_by`, `export_time`),
|
||||
KEY `idx_profit_report_export_status` (`export_status`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='毛利报表导出日志';
|
||||
@@ -16,6 +16,22 @@ CREATE TABLE IF NOT EXISTS `prc_profit_commission_rate` (
|
||||
KEY `idx_profit_commission_status` (`status`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='毛利报表业务员固定提成比例';
|
||||
|
||||
-- 毛利分析产品、订单维度导出日志及历史文件索引。
|
||||
CREATE TABLE IF NOT EXISTS `prc_profit_report_export` (
|
||||
`export_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '毛利报表导出ID',
|
||||
`dimension` varchar(16) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'PRODUCT产品维度,ORDER订单维度',
|
||||
`file_name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '下载文件名',
|
||||
`storage_key` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '下载目录下的文件Key',
|
||||
`row_count` int(11) DEFAULT NULL COMMENT '导出记录数',
|
||||
`export_status` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'PROCESSING生成中,SUCCESS成功,FAILED失败',
|
||||
`export_by` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '导出人',
|
||||
`export_time` datetime NOT NULL COMMENT '导出时间',
|
||||
`remark` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '失败原因',
|
||||
PRIMARY KEY (`export_id`),
|
||||
KEY `idx_profit_report_export_user_time` (`export_by`, `export_time`),
|
||||
KEY `idx_profit_report_export_status` (`export_status`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='毛利报表导出日志';
|
||||
|
||||
SET @index_exists := (
|
||||
SELECT COUNT(1) FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'prc_order_bill'
|
||||
|
||||
@@ -1,4 +1,15 @@
|
||||
import request, { download } from '@/utils/request'
|
||||
import request from '@/utils/request'
|
||||
import { tansParams } from '@/utils/bms'
|
||||
|
||||
function createProfitExport(url, params) {
|
||||
return request({
|
||||
url,
|
||||
method: 'post',
|
||||
data: params,
|
||||
transformRequest: [tansParams],
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
|
||||
})
|
||||
}
|
||||
|
||||
export function listProfitSummary(params) {
|
||||
return request({
|
||||
@@ -25,13 +36,30 @@ export function listProfitProducts(params) {
|
||||
}
|
||||
|
||||
export function exportProfitOrders(params) {
|
||||
return download('/report/profit/orders/export', params, '订单毛利报表.xlsx')
|
||||
return createProfitExport('/report/profit/orders/export', params)
|
||||
}
|
||||
|
||||
export function exportProfitProducts(params) {
|
||||
return download('/report/profit/products/export', params, '产品毛利报表.xlsx')
|
||||
return createProfitExport('/report/profit/products/export', params)
|
||||
}
|
||||
|
||||
export function listProfitExports(params) {
|
||||
return request({
|
||||
url: '/report/profit/exports',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
export function downloadProfitExport(exportId) {
|
||||
return request({
|
||||
url: '/report/profit/exports/' + exportId + '/download',
|
||||
method: 'get',
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
||||
/* 提成功能暂停使用,保留接口定义便于恢复。
|
||||
export function listProfitCommissionRates() {
|
||||
return request({
|
||||
url: '/report/profit/commission-rates',
|
||||
@@ -53,3 +81,4 @@ export function deleteProfitCommissionRate(rateId) {
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -65,6 +65,15 @@
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col v-if="dimension === 'order'" :xs="24" :sm="12" :lg="8">
|
||||
<el-form-item label="应收状态" class="filter-item">
|
||||
<el-select v-model="arBillStatus" clearable placeholder="全部状态" class="filter-control">
|
||||
<el-option label="未出账" value="UNBILLED" />
|
||||
<el-option label="部分出账" value="PARTIAL" />
|
||||
<el-option label="已出账" value="BILLED" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :lg="8" class="filter-actions-col">
|
||||
<div class="filter-item filter-actions">
|
||||
<el-button type="primary" icon="Search" @click="handleSearch">搜索</el-button>
|
||||
@@ -97,15 +106,19 @@
|
||||
<el-col :xs="12" :sm="8" :md="6">
|
||||
<div class="metric-item"><div class="metric-label">销售毛利</div><div class="metric-value profit-value">{{ money(summary.salesGrossProfit) }} <small>{{ rate(summary.salesGrossMarginRate) }}</small></div></div>
|
||||
</el-col>
|
||||
<!-- 提成功能暂停使用,保留代码便于恢复。
|
||||
<el-col :xs="12" :sm="8" :md="6">
|
||||
<div class="metric-item"><div class="metric-label">提成金额</div><div class="metric-value">{{ money(summary.commissionAmount) }}</div></div>
|
||||
</el-col>
|
||||
-->
|
||||
<el-col :xs="12" :sm="8" :md="6">
|
||||
<div class="metric-item"><div class="metric-label">价格缺失订单</div><div class="metric-value">{{ summary.incompleteOrderCount || 0 }}</div></div>
|
||||
</el-col>
|
||||
<!-- 提成功能暂停使用。
|
||||
<el-col :xs="12" :sm="8" :md="6">
|
||||
<div class="metric-item"><div class="metric-label">提成未计算订单</div><div class="metric-value">{{ summary.commissionMissingOrderCount || 0 }}</div></div>
|
||||
</el-col>
|
||||
-->
|
||||
</el-row>
|
||||
</el-card>
|
||||
</div>
|
||||
@@ -117,11 +130,18 @@
|
||||
<el-tab-pane label="订单维度" name="order" />
|
||||
</el-tabs>
|
||||
<div class="table-toolbar">
|
||||
<!-- 提成功能暂停使用。
|
||||
<el-button
|
||||
icon="Setting"
|
||||
v-hasPermi="['report:profit:commission:list']"
|
||||
@click="openCommissionRates"
|
||||
>提成比例设置</el-button>
|
||||
-->
|
||||
<el-button
|
||||
v-hasPermi="['report:profit:export']"
|
||||
icon="Tickets"
|
||||
@click="openExportLogs"
|
||||
>导出日志</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
@@ -151,10 +171,12 @@
|
||||
<el-table-column prop="salesAmount" label="销售价" min-width="130" align="right"><template #default="{ row }">{{ money(row.salesAmount) }}</template></el-table-column>
|
||||
<el-table-column prop="salesGrossProfit" label="销售毛利" min-width="130" align="right"><template #default="{ row }">{{ money(row.salesGrossProfit) }}</template></el-table-column>
|
||||
<el-table-column prop="salesGrossMarginRate" label="销售毛利率" min-width="120" align="right"><template #default="{ row }">{{ rate(row.salesGrossMarginRate) }}</template></el-table-column>
|
||||
<!-- 提成功能暂停使用。
|
||||
<el-table-column prop="commissionAmount" label="提成金额" min-width="120" align="right"><template #default="{ row }">{{ money(row.commissionAmount) }}</template></el-table-column>
|
||||
<el-table-column prop="commissionMissingOrderCount" label="提成未计算订单" width="150" align="right">
|
||||
<template #default="{ row }"><span class="success-value order-count-link" :class="{ 'is-disabled': !row.commissionMissingOrderCount }" @click.stop="openOrderList(row, 'COMMISSION_MISSING', '提成未计算订单')">{{ row.commissionMissingOrderCount }}</span></template>
|
||||
</el-table-column>
|
||||
-->
|
||||
<el-table-column prop="incompleteOrderCount" label="价格缺失订单" width="130" align="right">
|
||||
<template #default="{ row }"><span class="success-value order-count-link" :class="{ 'is-disabled': !row.incompleteOrderCount }" @click.stop="openOrderList(row, 'INCOMPLETE', '价格缺失订单')">{{ row.incompleteOrderCount }}</span></template>
|
||||
</el-table-column>
|
||||
@@ -177,8 +199,10 @@
|
||||
<el-table-column prop="salesAmount" label="销售价" min-width="130" align="right"><template #default="{ row }">{{ money(row.salesAmount) }}</template></el-table-column>
|
||||
<el-table-column prop="salesGrossProfit" label="销售毛利" min-width="130" align="right"><template #default="{ row }">{{ money(row.salesGrossProfit) }}</template></el-table-column>
|
||||
<el-table-column prop="salesGrossMarginRate" label="销售毛利率" min-width="120" align="right"><template #default="{ row }">{{ rate(row.salesGrossMarginRate) }}</template></el-table-column>
|
||||
<!-- 提成功能暂停使用。
|
||||
<el-table-column prop="commissionRate" label="提成比例" width="110" align="right"><template #default="{ row }">{{ commissionRateFormat(row.commissionRate) }}</template></el-table-column>
|
||||
<el-table-column prop="commissionAmount" label="提成金额" min-width="120" align="right"><template #default="{ row }">{{ money(row.commissionAmount) }}</template></el-table-column>
|
||||
-->
|
||||
<el-table-column prop="arBillStatus" label="应收状态" width="110" align="center">
|
||||
<template #default="{ row }">{{ arBillStatusLabel(row.arBillStatus) }}</template>
|
||||
</el-table-column>
|
||||
@@ -223,6 +247,37 @@
|
||||
<template #footer><el-button @click="orderListDialogVisible = false">关闭</el-button></template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="exportLogVisible" title="毛利分析导出日志" width="1000px" append-to-body>
|
||||
<el-table v-loading="exportLogLoading" :data="exportLogs" border stripe>
|
||||
<el-table-column prop="fileName" label="文件名" min-width="280" show-overflow-tooltip />
|
||||
<el-table-column prop="dimension" label="导出维度" width="120" align="center">
|
||||
<template #default="{ row }">{{ exportDimensionLabel(row.dimension) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="rowCount" label="数据条数" width="100" align="right" />
|
||||
<el-table-column prop="exportStatus" label="状态" width="100" align="center">
|
||||
<template #default="{ row }"><el-tag :type="exportStatusType(row.exportStatus)">{{ exportStatusLabel(row.exportStatus) }}</el-tag></template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="失败原因" min-width="180" show-overflow-tooltip />
|
||||
<el-table-column prop="exportBy" label="导出人" width="120" />
|
||||
<el-table-column prop="exportTime" label="导出时间" width="170" align="center"><template #default="{ row }">{{ parseTime(row.exportTime) }}</template></el-table-column>
|
||||
<el-table-column label="操作" width="90" fixed="right" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button v-if="row.exportStatus === 'SUCCESS'" link type="primary" @click="handleDownloadExport(row)">下载</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<template #empty><el-empty description="暂无导出记录" /></template>
|
||||
</el-table>
|
||||
<pagination
|
||||
v-show="exportLogTotal > 0"
|
||||
v-model:page="exportLogPageNum"
|
||||
v-model:limit="exportLogPageSize"
|
||||
:total="exportLogTotal"
|
||||
@pagination="loadExportLogs"
|
||||
/>
|
||||
<template #footer><el-button @click="exportLogVisible = false">关闭</el-button></template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 提成设置与编辑弹窗暂停使用。
|
||||
<el-dialog v-model="commissionDialogVisible" title="业务员固定提成比例" width="760px" append-to-body>
|
||||
<div class="commission-toolbar">
|
||||
<span class="commission-tip">按业务员编码配置,比例输入百分数,例如 5 表示 5%。</span>
|
||||
@@ -255,17 +310,22 @@
|
||||
<el-button @click="rateFormVisible = false">取消</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
-->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="ProfitReport">
|
||||
import { deleteProfitCommissionRate, exportProfitOrders, exportProfitProducts, listProfitCommissionRates, listProfitOrders, listProfitProducts, listProfitSummary, saveProfitCommissionRate } from '@/api/report/profit'
|
||||
import { downloadProfitExport, exportProfitOrders, exportProfitProducts, listProfitExports, listProfitOrders, listProfitProducts, listProfitSummary } from '@/api/report/profit'
|
||||
// 提成功能暂停使用:import { deleteProfitCommissionRate, listProfitCommissionRates, saveProfitCommissionRate } from '@/api/report/profit'
|
||||
import { parseTime } from '@/utils/bms'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { saveAs } from 'file-saver'
|
||||
// 提成功能暂停使用:import { ElMessageBox } from 'element-plus'
|
||||
|
||||
const dimension = ref('product')
|
||||
const multiValueFilterLimit = 2000
|
||||
const dateRange = ref([formatLocalDate(-30), formatLocalDate(0)])
|
||||
const arBillStatus = ref('')
|
||||
const query = reactive({
|
||||
orderNo: '',
|
||||
customerCode: '',
|
||||
@@ -278,6 +338,12 @@ const rows = ref([])
|
||||
let rowsRequestVersion = 0
|
||||
const loading = ref(false)
|
||||
const exporting = ref(false)
|
||||
const exportLogVisible = ref(false)
|
||||
const exportLogLoading = ref(false)
|
||||
const exportLogs = ref([])
|
||||
const exportLogPageNum = ref(1)
|
||||
const exportLogPageSize = ref(10)
|
||||
const exportLogTotal = ref(0)
|
||||
const pageNum = ref(1)
|
||||
const pageSize = ref(10)
|
||||
const total = ref(0)
|
||||
@@ -290,6 +356,7 @@ const orderListPageNum = ref(1)
|
||||
const orderListPageSize = ref(10)
|
||||
const orderListContext = ref(null)
|
||||
let orderListRequestVersion = 0
|
||||
/* 提成表单状态与初始化暂停使用,保留代码便于恢复。
|
||||
const commissionDialogVisible = ref(false)
|
||||
const commissionLoading = ref(false)
|
||||
const commissionRates = ref([])
|
||||
@@ -313,6 +380,7 @@ function createRateForm(row = {}) {
|
||||
remark: row.remark || ''
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
function formatLocalDate(offset) {
|
||||
const date = new Date()
|
||||
@@ -323,8 +391,9 @@ function formatLocalDate(offset) {
|
||||
return `${year}-${month}-${day}`
|
||||
}
|
||||
|
||||
function buildQuery(paged = true) {
|
||||
function buildQuery(paged = true, includeArBillStatus = dimension.value === 'order') {
|
||||
const params = { ...query }
|
||||
if (includeArBillStatus && arBillStatus.value) params.arBillStatus = arBillStatus.value
|
||||
if (dateRange.value?.[0]) params.beginBizDate = dateRange.value[0] + ' 00:00:00'
|
||||
if (dateRange.value?.[1]) params.endBizDate = dateRange.value[1] + ' 23:59:59'
|
||||
if (paged) {
|
||||
@@ -380,20 +449,23 @@ function handleSearch() {
|
||||
|
||||
function handleReset() {
|
||||
Object.keys(query).forEach(key => { query[key] = '' })
|
||||
arBillStatus.value = ''
|
||||
dateRange.value = [formatLocalDate(-30), formatLocalDate(0)]
|
||||
handleSearch()
|
||||
}
|
||||
|
||||
function handleDimensionChange() {
|
||||
if (dimension.value !== 'order') arBillStatus.value = ''
|
||||
pageNum.value = 1
|
||||
rows.value = []
|
||||
total.value = 0
|
||||
loadRows()
|
||||
Promise.all([loadSummary(), loadRows()])
|
||||
}
|
||||
|
||||
function openOrderList(row, detailType, label) {
|
||||
if (!validateMultiValueFilters()) return
|
||||
const count = detailType === 'ALL' ? row.orderCount : detailType === 'COMMISSION_MISSING' ? row.commissionMissingOrderCount : row.incompleteOrderCount
|
||||
// 提成未计算订单下钻暂停使用:detailType === 'COMMISSION_MISSING' ? row.commissionMissingOrderCount
|
||||
const count = detailType === 'ALL' ? row.orderCount : row.incompleteOrderCount
|
||||
if (!count) return
|
||||
orderListTitle.value = `${label}订单列表`
|
||||
orderListContext.value = {
|
||||
@@ -448,11 +520,13 @@ function rate(value) {
|
||||
return Number.isFinite(number) ? number.toFixed(2) + '%' : '-'
|
||||
}
|
||||
|
||||
/* 提成比例格式化暂停使用。
|
||||
function commissionRateFormat(value) {
|
||||
if (value === null || value === undefined || value === '') return '-'
|
||||
const number = Number(value)
|
||||
return Number.isFinite(number) ? number.toFixed(4) + '%' : '-'
|
||||
}
|
||||
*/
|
||||
|
||||
function arBillStatusLabel(value) {
|
||||
const labels = {
|
||||
@@ -463,13 +537,73 @@ function arBillStatusLabel(value) {
|
||||
return labels[value] || value || '-'
|
||||
}
|
||||
|
||||
function handleExport() {
|
||||
async function handleExport() {
|
||||
if (!validateMultiValueFilters()) return
|
||||
exporting.value = true
|
||||
const exporter = dimension.value === 'product' ? exportProfitProducts : exportProfitOrders
|
||||
exporter(buildQuery(false)).finally(() => { exporting.value = false })
|
||||
try {
|
||||
const response = await exporter(buildQuery(false))
|
||||
const exportLog = response.data
|
||||
const file = await downloadProfitExport(exportLog.exportId)
|
||||
if (file.type?.includes('json')) {
|
||||
const error = JSON.parse(await file.text())
|
||||
throw new Error(error.msg || '下载导出文件失败')
|
||||
}
|
||||
saveAs(file, exportLog.fileName)
|
||||
ElMessage.success('报表已导出,记录已保存到导出日志')
|
||||
} catch (error) {
|
||||
ElMessage.error(error?.message || '报表导出失败')
|
||||
} finally {
|
||||
exporting.value = false
|
||||
if (exportLogVisible.value) loadExportLogs()
|
||||
}
|
||||
}
|
||||
|
||||
function openExportLogs() {
|
||||
exportLogPageNum.value = 1
|
||||
exportLogVisible.value = true
|
||||
loadExportLogs()
|
||||
}
|
||||
|
||||
function loadExportLogs() {
|
||||
exportLogLoading.value = true
|
||||
listProfitExports({ pageNum: exportLogPageNum.value, pageSize: exportLogPageSize.value }).then(response => {
|
||||
exportLogs.value = response.rows || []
|
||||
exportLogTotal.value = response.total || 0
|
||||
}).catch(() => {
|
||||
exportLogs.value = []
|
||||
exportLogTotal.value = 0
|
||||
}).finally(() => {
|
||||
exportLogLoading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
function exportDimensionLabel(value) {
|
||||
return value === 'PRODUCT' ? '产品维度' : value === 'ORDER' ? '订单维度' : value || '-'
|
||||
}
|
||||
|
||||
function exportStatusLabel(value) {
|
||||
return value === 'PROCESSING' ? '生成中' : value === 'SUCCESS' ? '成功' : value === 'FAILED' ? '失败' : value || '-'
|
||||
}
|
||||
|
||||
function exportStatusType(value) {
|
||||
return value === 'SUCCESS' ? 'success' : value === 'FAILED' ? 'danger' : 'info'
|
||||
}
|
||||
|
||||
async function handleDownloadExport(row) {
|
||||
try {
|
||||
const file = await downloadProfitExport(row.exportId)
|
||||
if (file.type?.includes('json')) {
|
||||
const error = JSON.parse(await file.text())
|
||||
throw new Error(error.msg || '下载导出文件失败')
|
||||
}
|
||||
saveAs(file, row.fileName)
|
||||
} catch (error) {
|
||||
ElMessage.error(error?.message || '下载导出文件失败')
|
||||
}
|
||||
}
|
||||
|
||||
/* 提成配置交互暂停使用。
|
||||
function openCommissionRates() {
|
||||
commissionDialogVisible.value = true
|
||||
commissionLoading.value = true
|
||||
@@ -514,6 +648,7 @@ function handleDeleteRate(row) {
|
||||
}
|
||||
})
|
||||
}
|
||||
*/
|
||||
|
||||
handleSearch()
|
||||
</script>
|
||||
@@ -661,6 +796,7 @@ handleSearch()
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
/* 提成设置弹窗样式暂停使用。
|
||||
.commission-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -673,6 +809,7 @@ handleSearch()
|
||||
color: var(--el-text-color-secondary);
|
||||
font-size: 13px;
|
||||
}
|
||||
*/
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.summary-list {
|
||||
|
||||
Reference in New Issue
Block a user