增加导入附件的查看记录

This commit is contained in:
wuweihua
2026-10-15 15:02:23 +08:00
parent c704021f2f
commit 41ce05a08a
14 changed files with 585 additions and 13 deletions
@@ -165,8 +165,8 @@ public class TabOrderMonitorController extends BaseController
int fail = data.get("fail") instanceof Number ? ((Number) data.get("fail")).intValue() : 0;
String action = rows.size() == 1 ? "ONE" : "SELECTED";
String bizId = firstOrderBizId(rows, action);
String status = fail > 0 && ok == 0 ? "FAIL" : "SUCCESS";
String err = fail > 0 ? ("fail=" + fail) : null;
String status = fail > 0 ? "FAIL" : "SUCCESS";
String err = fail > 0 ? ("fail=" + fail + ", ok=" + ok) : null;
TabOrderSyncEsLog.save(billSearchStore, bizId, action, rows, data, status, err);
return success(data);
}
@@ -1,5 +1,6 @@
package com.bms.web.controller.price;
import java.io.ByteArrayInputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
@@ -25,8 +26,11 @@ import com.bms.common.core.page.TableDataInfo;
import com.bms.common.enums.BusinessType;
import com.bms.common.utils.DateUtils;
import com.bms.common.utils.MessageUtils;
import com.bms.common.utils.SecurityUtils;
import com.bms.common.utils.StringUtils;
import com.bms.common.utils.poi.ExcelUtil;
import com.bms.system.domain.BmsBizAttachment;
import com.bms.system.service.IBmsBizAttachmentService;
import com.bms.price.domain.BatchAddIncomeBillFeeTask;
import com.bms.price.domain.ChargeWeightImportTask;
import com.bms.price.domain.PrcBillingTask;
@@ -66,6 +70,9 @@ public class BillingController extends BaseController
@Autowired
private IPrcBillingTaskService prcBillingTaskService;
@Autowired
private IBmsBizAttachmentService bizAttachmentService;
/**
* Historical quote list.
*/
@@ -360,12 +367,36 @@ public class BillingController extends BaseController
@PostMapping("/bill/chargeWeight/importData")
public AjaxResult importChargeWeight(MultipartFile file) throws Exception
{
if (file == null || file.isEmpty())
{
return error("file required");
}
byte[] bytes = file.getBytes();
String originalName = file.getOriginalFilename();
ExcelUtil<ChargeWeightImportRow> util = new ExcelUtil<ChargeWeightImportRow>(ChargeWeightImportRow.class);
List<ChargeWeightImportRow> rows = util.importExcel(file.getInputStream());
List<ChargeWeightImportRow> rows = util.importExcel(new ByteArrayInputStream(bytes));
String taskId = prcOrderBillService.submitImportChargeWeight(rows);
Map<String, Object> payload = new HashMap<String, Object>();
payload.put("taskId", taskId);
return success(payload);
try
{
BmsBizAttachment att = bizAttachmentService.saveUpload(
BmsBizAttachment.BIZ_CHARGE_WEIGHT_IMPORT, taskId, bytes, originalName,
SecurityUtils.getUsername(), null);
Map<String, Object> payload = new HashMap<String, Object>();
payload.put("taskId", taskId);
if (att != null)
{
payload.put("attachmentId", att.getAttachmentId());
}
return success(payload);
}
catch (Exception e)
{
// Import task already queued; attachment failure should not block rebill
Map<String, Object> payload = new HashMap<String, Object>();
payload.put("taskId", taskId);
payload.put("attachmentWarn", e.getMessage());
return success(payload);
}
}
@PreAuthorize("@ss.hasPermi('price:billing:chargeWeightEdit')")
@@ -379,4 +410,21 @@ public class BillingController extends BaseController
}
return success(task);
}
/**
* List charge-weight import Excel attachment records.
*/
@PreAuthorize("@ss.hasPermi('price:billing:chargeWeightEdit')")
@GetMapping("/bill/chargeWeight/import/attachments")
public TableDataInfo listChargeWeightImportAttachments(BmsBizAttachment query)
{
if (query == null)
{
query = new BmsBizAttachment();
}
query.setBizType(BmsBizAttachment.BIZ_CHARGE_WEIGHT_IMPORT);
startPage();
List<BmsBizAttachment> list = bizAttachmentService.selectBmsBizAttachmentList(query);
return getDataTable(list);
}
}
@@ -42,4 +42,32 @@ public final class TabOrderSyncEsLog
String st = StringUtils.isEmpty(status) ? EsBizLogSupport.STATUS_SUCCESS : status;
store.save(EsLogType.ORDER_SOURCE_SYNC, bizId, reqJson, respJson, st, errorMessage);
}
/** Persist one failed sync order so it appears in order-source operation log. */
public static void saveOneFail(IBillSearchStore store, Object row, Object response, String errorMessage)
{
String orderId = null;
if (row instanceof com.bms.price.domain.vo.TabOrderMonitorVo)
{
orderId = ((com.bms.price.domain.vo.TabOrderMonitorVo) row).getOrderId();
}
else if (row instanceof Map)
{
Object v = ((Map<?, ?>) row).get("orderId");
if (v != null)
{
orderId = String.valueOf(v);
}
}
String bizId;
if (StringUtils.isEmpty(orderId))
{
bizId = "ONE_FAIL_" + System.currentTimeMillis();
}
else
{
bizId = "ONE_" + orderId.trim();
}
save(store, bizId, "ONE_FAIL", row, response, EsBizLogSupport.STATUS_FAIL, errorMessage);
}
}
@@ -84,6 +84,8 @@ public class TabOrderSyncAsyncRunner
AtomicInteger processed = new AtomicInteger(0);
AtomicInteger ok = new AtomicInteger(0);
AtomicInteger fail = new AtomicInteger(0);
List<Map<String, Object>> failDetails = java.util.Collections.synchronizedList(
new ArrayList<Map<String, Object>>());
int pageNum = 1;
while (true)
{
@@ -102,7 +104,7 @@ public class TabOrderSyncAsyncRunner
{
final TabOrderMonitorVo one = row;
jobs.add(() -> {
boolean success = syncOne(one);
boolean success = syncOne(one, failDetails);
if (success)
{
ok.incrementAndGet();
@@ -137,7 +139,10 @@ public class TabOrderSyncAsyncRunner
resp.put("ok", Integer.valueOf(ok.get()));
resp.put("fail", Integer.valueOf(fail.get()));
resp.put("threads", Integer.valueOf(threads));
TabOrderSyncEsLog.save(billSearchStore, asyncTaskId, "FILTER_DONE", query, resp, "SUCCESS", null);
resp.put("failDetails", truncateFailDetails(failDetails));
String doneStatus = fail.get() > 0 ? "FAIL" : "SUCCESS";
String doneErr = fail.get() > 0 ? ("fail=" + fail.get() + ", ok=" + ok.get()) : null;
TabOrderSyncEsLog.save(billSearchStore, asyncTaskId, "FILTER_DONE", query, resp, doneStatus, doneErr);
log.info("orderSource sync done asyncTaskId={} total={} ok={} fail={} threads={}",
asyncTaskId, total, ok.get(), fail.get(), threads);
}
@@ -253,12 +258,18 @@ public class TabOrderSyncAsyncRunner
return data;
}
private boolean syncOne(TabOrderMonitorVo row)
private boolean syncOne(TabOrderMonitorVo row, List<Map<String, Object>> failDetails)
{
try
{
PrcBillingTask task = billingTaskService.submitAndProcess(toSubmit(row));
return task != null && BillTaskSuccessStatus.SUCCESS.getCode().equals(task.getSuccessStatus());
boolean success = task != null
&& BillTaskSuccessStatus.SUCCESS.getCode().equals(task.getSuccessStatus());
if (!success)
{
collectFailDetail(failDetails, row, task, null);
}
return success;
}
catch (RuntimeException e)
{
@@ -266,10 +277,62 @@ public class TabOrderSyncAsyncRunner
row == null ? null : row.getOrderId(),
row == null ? null : row.getTransferOrderId(),
e.getMessage());
collectFailDetail(failDetails, row, null, e.getMessage());
return false;
}
}
private static final int FAIL_DETAIL_MAX = 200;
private static void collectFailDetail(List<Map<String, Object>> failDetails, TabOrderMonitorVo row,
PrcBillingTask task, String exceptionMessage)
{
if (failDetails == null)
{
return;
}
Map<String, Object> item = new LinkedHashMap<String, Object>();
item.put("orderId", row == null ? null : row.getOrderId());
item.put("transferOrderId", row == null ? null : row.getTransferOrderId());
String err = exceptionMessage;
if (task != null)
{
item.put("successStatus", task.getSuccessStatus());
item.put("billType", task.getBillType());
item.put("taskId", task.getTaskId());
if (StringUtils.isEmpty(err))
{
err = task.getErrorMessage();
}
}
if (StringUtils.isEmpty(err))
{
err = "sync failed";
}
item.put("errorMessage", err);
synchronized (failDetails)
{
if (failDetails.size() >= FAIL_DETAIL_MAX)
{
return;
}
failDetails.add(item);
}
}
private static List<Map<String, Object>> truncateFailDetails(List<Map<String, Object>> failDetails)
{
if (failDetails == null || failDetails.isEmpty())
{
return java.util.Collections.emptyList();
}
if (failDetails.size() <= FAIL_DETAIL_MAX)
{
return new ArrayList<Map<String, Object>>(failDetails);
}
return new ArrayList<Map<String, Object>>(failDetails.subList(0, FAIL_DETAIL_MAX));
}
private static void invokeAllQuiet(ExecutorService pool, List<Callable<Boolean>> jobs) throws InterruptedException
{
List<Future<Boolean>> futures = pool.invokeAll(jobs);
@@ -0,0 +1,30 @@
package com.bms.system.domain;
import com.bms.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 公共业务附件 bms_biz_attachment
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class BmsBizAttachment extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** 批量修改计费重导入 */
public static final String BIZ_CHARGE_WEIGHT_IMPORT = "CHARGE_WEIGHT_IMPORT";
private Long attachmentId;
/** 业务类型 */
private String bizType;
/** 业务关联ID */
private String bizId;
private String fileName;
private String filePath;
private Long fileSize;
private String contentType;
private String fileExtension;
private String delFlag;
}
@@ -0,0 +1,18 @@
package com.bms.system.mapper;
import java.util.List;
import com.bms.system.domain.BmsBizAttachment;
/** Common biz attachment mapper */
public interface BmsBizAttachmentMapper
{
BmsBizAttachment selectBmsBizAttachmentById(Long attachmentId);
List<BmsBizAttachment> selectBmsBizAttachmentList(BmsBizAttachment query);
int insertBmsBizAttachment(BmsBizAttachment row);
int updateBmsBizAttachment(BmsBizAttachment row);
int deleteBmsBizAttachmentByIds(Long[] attachmentIds);
}
@@ -0,0 +1,18 @@
package com.bms.system.service;
import java.util.List;
import com.bms.system.domain.BmsBizAttachment;
/** 公共业务附件 */
public interface IBmsBizAttachmentService
{
BmsBizAttachment selectBmsBizAttachmentById(Long attachmentId);
List<BmsBizAttachment> selectBmsBizAttachmentList(BmsBizAttachment query);
/**
* 落盘保存上传文件并写附件记录
*/
BmsBizAttachment saveUpload(String bizType, String bizId, byte[] bytes, String filename,
String operName, String remark) throws Exception;
}
@@ -0,0 +1,104 @@
package com.bms.system.service.impl;
import java.io.File;
import java.io.FileOutputStream;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.bms.common.config.BmsConfig;
import com.bms.common.exception.ServiceException;
import com.bms.common.utils.DateUtils;
import com.bms.common.utils.StringUtils;
import com.bms.common.utils.file.FileUploadUtils;
import com.bms.common.utils.uuid.IdUtils;
import com.bms.system.domain.BmsBizAttachment;
import com.bms.system.mapper.BmsBizAttachmentMapper;
import com.bms.system.service.IBmsBizAttachmentService;
@Service
public class BmsBizAttachmentServiceImpl implements IBmsBizAttachmentService
{
private static final String SUB_DIR = "biz/attachment";
@Autowired
private BmsBizAttachmentMapper attachmentMapper;
@Override
public BmsBizAttachment selectBmsBizAttachmentById(Long attachmentId)
{
return attachmentMapper.selectBmsBizAttachmentById(attachmentId);
}
@Override
public List<BmsBizAttachment> selectBmsBizAttachmentList(BmsBizAttachment query)
{
List<BmsBizAttachment> list = attachmentMapper.selectBmsBizAttachmentList(query);
return list == null ? Collections.emptyList() : list;
}
@Override
public BmsBizAttachment saveUpload(String bizType, String bizId, byte[] bytes, String filename,
String operName, String remark) throws Exception
{
if (StringUtils.isEmpty(bizType))
{
throw new ServiceException("bizType required");
}
if (bytes == null || bytes.length == 0)
{
throw new ServiceException("file empty");
}
String originalName = StringUtils.isNotEmpty(filename) ? filename : "upload.bin";
String ext = FilenameUtils.getExtension(originalName);
if (StringUtils.isEmpty(ext))
{
ext = "bin";
}
ext = ext.toLowerCase(Locale.ROOT);
String uploadDir = BmsConfig.getUploadPath() + File.separator + SUB_DIR;
String pathName = DateUtils.datePath() + "/" + IdUtils.fastSimpleUUID() + "." + ext;
File dest = FileUploadUtils.getAbsoluteFile(uploadDir, pathName);
FileOutputStream fos = null;
try
{
fos = new FileOutputStream(dest);
fos.write(bytes);
}
finally
{
IOUtils.close(fos);
}
String storedPath = FileUploadUtils.getPathFileName(uploadDir, pathName);
BmsBizAttachment row = new BmsBizAttachment();
row.setBizType(bizType.trim());
row.setBizId(bizId);
row.setFileName(originalName);
row.setFilePath(storedPath);
row.setFileSize(Long.valueOf(bytes.length));
row.setContentType(resolveContentType(ext));
row.setFileExtension(ext);
row.setRemark(remark);
row.setCreateBy(operName);
attachmentMapper.insertBmsBizAttachment(row);
return row;
}
private static String resolveContentType(String ext)
{
if ("xls".equals(ext))
{
return "application/vnd.ms-excel";
}
if ("xlsx".equals(ext))
{
return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
}
return "";
}
}
@@ -0,0 +1,106 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bms.system.mapper.BmsBizAttachmentMapper">
<resultMap type="BmsBizAttachment" id="BmsBizAttachmentResult">
<id property="attachmentId" column="attachment_id" />
<result property="bizType" column="biz_type" />
<result property="bizId" column="biz_id" />
<result property="fileName" column="file_name" />
<result property="filePath" column="file_path" />
<result property="fileSize" column="file_size" />
<result property="contentType" column="content_type" />
<result property="fileExtension" column="file_extension" />
<result property="remark" column="remark" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
<result property="delFlag" column="del_flag" />
</resultMap>
<sql id="selectBmsBizAttachmentVo">
select attachment_id, biz_type, biz_id, file_name, file_path, file_size, content_type,
file_extension, remark, create_by, create_time, update_by, update_time, del_flag
from bms_biz_attachment
</sql>
<select id="selectBmsBizAttachmentById" parameterType="Long" resultMap="BmsBizAttachmentResult">
<include refid="selectBmsBizAttachmentVo"/>
where attachment_id = #{attachmentId} and del_flag = '0'
</select>
<select id="selectBmsBizAttachmentList" parameterType="BmsBizAttachment" resultMap="BmsBizAttachmentResult">
<include refid="selectBmsBizAttachmentVo"/>
<where>
del_flag = '0'
<if test="bizType != null and bizType != ''">
AND biz_type = #{bizType}
</if>
<if test="bizId != null and bizId != ''">
AND biz_id = #{bizId}
</if>
<if test="fileName != null and fileName != ''">
AND file_name like concat('%', #{fileName}, '%')
</if>
<if test="createBy != null and createBy != ''">
AND create_by like concat('%', #{createBy}, '%')
</if>
<if test="params != null and params.beginTime != null and params.beginTime != ''">
AND create_time &gt;= #{params.beginTime}
</if>
<if test="params != null and params.endTime != null and params.endTime != ''">
AND create_time &lt;= #{params.endTime}
</if>
</where>
order by attachment_id desc
</select>
<insert id="insertBmsBizAttachment" parameterType="BmsBizAttachment" useGeneratedKeys="true" keyProperty="attachmentId">
insert into bms_biz_attachment (
<if test="bizType != null and bizType != ''">biz_type,</if>
<if test="bizId != null">biz_id,</if>
<if test="fileName != null and fileName != ''">file_name,</if>
<if test="filePath != null and filePath != ''">file_path,</if>
<if test="fileSize != null">file_size,</if>
<if test="contentType != null">content_type,</if>
<if test="fileExtension != null">file_extension,</if>
<if test="remark != null">remark,</if>
<if test="createBy != null and createBy != ''">create_by,</if>
create_time,
del_flag
) values (
<if test="bizType != null and bizType != ''">#{bizType},</if>
<if test="bizId != null">#{bizId},</if>
<if test="fileName != null and fileName != ''">#{fileName},</if>
<if test="filePath != null and filePath != ''">#{filePath},</if>
<if test="fileSize != null">#{fileSize},</if>
<if test="contentType != null">#{contentType},</if>
<if test="fileExtension != null">#{fileExtension},</if>
<if test="remark != null">#{remark},</if>
<if test="createBy != null and createBy != ''">#{createBy},</if>
sysdate(),
'0'
)
</insert>
<update id="updateBmsBizAttachment" parameterType="BmsBizAttachment">
update bms_biz_attachment
<set>
<if test="bizId != null">biz_id = #{bizId},</if>
<if test="remark != null">remark = #{remark},</if>
<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
update_time = sysdate()
</set>
where attachment_id = #{attachmentId}
</update>
<update id="deleteBmsBizAttachmentByIds" parameterType="Long">
update bms_biz_attachment set del_flag = '2' where attachment_id in
<foreach collection="array" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</update>
</mapper>
@@ -0,0 +1,22 @@
-- 公共业务附件表(可复用:批量修改计费重导入等)
SET NAMES utf8mb4;
CREATE TABLE IF NOT EXISTS bms_biz_attachment (
attachment_id bigint(20) NOT NULL AUTO_INCREMENT COMMENT '附件ID',
biz_type varchar(64) NOT NULL COMMENT '业务类型(如 CHARGE_WEIGHT_IMPORT)',
biz_id varchar(64) DEFAULT NULL COMMENT '业务关联ID(如导入任务taskId)',
file_name varchar(255) NOT NULL COMMENT '文件原始名称',
file_path varchar(500) NOT NULL COMMENT '存储路径(相对路径)',
file_size bigint(20) DEFAULT 0 COMMENT '文件大小(字节)',
content_type varchar(100) DEFAULT '' COMMENT 'MIME类型',
file_extension varchar(20) DEFAULT '' COMMENT '扩展名',
remark varchar(500) DEFAULT NULL COMMENT '备注',
create_by varchar(64) DEFAULT '' COMMENT '创建人',
create_time datetime DEFAULT NULL COMMENT '创建时间',
update_by varchar(64) DEFAULT '' COMMENT '更新人',
update_time datetime DEFAULT NULL COMMENT '更新时间',
del_flag char(1) DEFAULT '0' COMMENT '删除标志(0存在 2删除)',
PRIMARY KEY (attachment_id),
KEY idx_biz_attach_type_time (biz_type, create_time),
KEY idx_biz_attach_biz_id (biz_type, biz_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='公共业务附件';
+9
View File
@@ -277,3 +277,12 @@ export async function downloadChargeWeightTemplate(data, filename) {
loading.close()
}
}
/** 批量修改计费重导入附件记录 */
export function listChargeWeightImportAttachments(query) {
return request({
url: '/price/billing/bill/chargeWeight/import/attachments',
method: 'get',
params: query
})
}
@@ -35,6 +35,14 @@
<span class="err-text">{{ detail.errorMessage }}</span>
</el-descriptions-item>
</el-descriptions>
<div v-if="failRows.length" class="json-panel">
<div class="json-panel__head"><span>失败明细(共 {{ failRows.length }} 单)</span></div>
<el-table :data="failRows" border size="small" max-height="280" class="fail-table">
<el-table-column label="订单号" prop="orderId" min-width="160" show-overflow-tooltip />
<el-table-column label="转单号" prop="transferOrderId" min-width="140" show-overflow-tooltip />
<el-table-column label="错误信息" prop="errorMessage" min-width="220" show-overflow-tooltip />
</el-table>
</div>
<div class="json-panel">
<div class="json-panel__head"><span>请求报文</span></div>
<pre class="code-pre">{{ formatJson(detail.requestJson) }}</pre>
@@ -74,7 +82,7 @@ const searchColumns = [
]
const columns = [
{ label: '操作', prop: 'actionName', width: 120, slot: 'actionName' },
{ label: '操作', prop: 'actionName', width: 150, slot: 'actionName' },
{ label: '业务ID', prop: 'bizId', minWidth: 180, showOverflowTooltip: true },
{ label: '状态', prop: 'status', align: 'center', width: 90, slot: 'status' },
{ label: '写入时间', prop: 'updateTime', align: 'center', width: 170 },
@@ -93,12 +101,41 @@ function parseReq(row) {
function actionLabel(row) {
const action = parseReq(row).action
if (action === 'FILTER') return '筛选同步'
if (action === 'FILTER_DONE') return '筛选完成'
if (action === 'SELECTED') return '同步选中'
if (action === 'FILTER_DONE') {
return row.status === 'FAIL' ? '筛选完成(有失败)' : '筛选完成'
}
if (action === 'SELECTED') {
return row.status === 'FAIL' ? '同步选中(有失败)' : '同步选中'
}
if (action === 'ONE') return '单条同步'
if (action === 'ONE_FAIL') return '同步失败'
return action || '-'
}
const failRows = computed(() => {
if (!detail.value) return []
const resp = parseResp(detail.value)
if (Array.isArray(resp.failDetails) && resp.failDetails.length) {
return resp.failDetails
}
if (Array.isArray(resp.details) && resp.details.length) {
return resp.details.filter(d => {
const st = d && d.successStatus
return st && String(st).toUpperCase() !== 'SUCCESS'
})
}
return []
})
function parseResp(row) {
if (!row || !row.responseJson) return {}
try {
return typeof row.responseJson === 'object' ? row.responseJson : JSON.parse(row.responseJson)
} catch (e) {
return {}
}
}
function queryList(params) {
return listOrderSourceSyncLog(params)
}
@@ -143,6 +180,9 @@ defineExpose({ open })
margin-bottom: 6px;
font-weight: 600;
}
.fail-table {
margin-top: 6px;
}
.code-pre {
margin: 0;
padding: 10px 12px;
@@ -95,6 +95,15 @@
@click="openChargeWeightImport"
>批量修改计费重</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="info"
plain
icon="Document"
v-hasPermi="['price:billing:chargeWeightEdit']"
@click="openChargeWeightImportAttach"
>导入记录</el-button>
</el-col>
</template>
<template #col-action="{ row }">
<el-button link type="primary" icon="View" @click="handleView(row)">查看</el-button>
@@ -151,6 +160,7 @@
<div class="cw-fill-hint">勾选后下载模板会写入筛选结果的订单号、客户代码;人工修改计费重列留空待填</div>
</template>
</excel-import-dialog>
<charge-weight-import-attach-drawer ref="cwImportAttachRef" />
<el-dialog
v-model="cwImportProgressVisible"
title="正在导入修改计费重"
@@ -181,6 +191,7 @@ import BillDetail from './components/BillDetail.vue'
import BatchAddIncomeFeeDialog from './components/BatchAddIncomeFeeDialog.vue'
import EditChargeWeightDialog from './components/EditChargeWeightDialog.vue'
import ExcelImportDialog from '@/components/ExcelImportDialog'
import ChargeWeightImportAttachDrawer from './components/ChargeWeightImportAttachDrawer.vue'
// 订单号下拉远程搜索:返回匹配的订单号列表(最多 20 条)
function searchOrderNoOptions(keyword) {
@@ -218,6 +229,7 @@ const refundingKey = ref(null)
const editCwOpen = ref(false)
const editCwRow = ref(null)
const chargeWeightImportRef = ref()
const cwImportAttachRef = ref()
const chargeWeightImportDesc = [
'模板列:订单号、客户、人工修改计费重(kg)',
'客户可填名称或代码,须与订单客户一致',
@@ -440,6 +452,10 @@ async function downloadChargeWeightImportTemplate() {
await downloadChargeWeightTemplate(payload)
}
function openChargeWeightImportAttach() {
cwImportAttachRef.value?.open?.()
}
function openChargeWeightImport() {
cwFillByFilter.value = false
chargeWeightImportRef.value?.open?.()
@@ -0,0 +1,70 @@
<template>
<el-drawer v-model="visible" size="860px" :title="drawerTitle" append-to-body destroy-on-close>
<basic-table
v-if="visible"
:columns="columns"
:search-columns="searchColumns"
:query="queryList"
row-key="attachmentId"
:page-size="10"
:selection="false"
:show-add="false"
>
<template #col-fileSize="{ row }">
{{ formatSize(row.fileSize) }}
</template>
<template #col-action="{ row }">
<el-button link type="primary" :disabled="!row.filePath" @click="handleDownload(row)">下载</el-button>
</template>
</basic-table>
</el-drawer>
</template>
<script setup>
import { listChargeWeightImportAttachments } from '@/api/price/billing'
const { proxy } = getCurrentInstance()
const visible = ref(false)
const drawerTitle = '批量修改计费重导入记录'
const searchColumns = [
{ label: '文件名', prop: 'fileName', component: 'input', placeholder: '文件名', width: '200px' },
{ label: '上传人', prop: 'createBy', component: 'input', placeholder: '上传人', width: '140px' }
]
const columns = [
{ label: '文件名称', prop: 'fileName', minWidth: 220, showOverflowTooltip: true },
{ label: '任务ID', prop: 'bizId', minWidth: 180, showOverflowTooltip: true },
{ label: '大小', prop: 'fileSize', width: 100, align: 'right', slot: 'fileSize' },
{ label: '上传人', prop: 'createBy', width: 110, align: 'center', showOverflowTooltip: true },
{ label: '上传时间', prop: 'createTime', width: 170, align: 'center' },
{ label: '操作', prop: 'action', width: 90, align: 'center', fixed: 'right', slot: 'action', showInToolbar: false }
]
function queryList(params) {
return listChargeWeightImportAttachments(params)
}
function formatSize(bytes) {
const n = Number(bytes)
if (!n || n < 0) return '-'
if (n < 1024) return n + ' B'
if (n < 1024 * 1024) return (n / 1024).toFixed(1) + ' KB'
return (n / (1024 * 1024)).toFixed(2) + ' MB'
}
function handleDownload(row) {
if (!row || !row.filePath) {
proxy.$modal.msgWarning('文件路径不存在')
return
}
proxy.$download.resource(row.filePath)
}
function open() {
visible.value = true
}
defineExpose({ open })
</script>