This commit is contained in:
zpc 2026-01-04 23:02:53 +08:00
parent 07aa115282
commit e3882d7366
5 changed files with 121 additions and 6 deletions

View File

@ -171,12 +171,12 @@ namespace ZR.Admin.WebApi.Controllers.Business
} }
/// <summary> /// <summary>
/// 导出工作记录 /// 导出工作记录异步生成返回下载URL
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[Log(Title = "工作记录", BusinessType = BusinessType.EXPORT, IsSaveResponseData = false)] [Log(Title = "工作记录", BusinessType = BusinessType.EXPORT, IsSaveResponseData = false)]
[HttpGet("export")] [HttpGet("export")]
[ActionPermissionFilter(Permission = "camworkrecord:export")] // [ActionPermissionFilter(Permission = "camworkrecord:export")]
public IActionResult Export([FromQuery] CamWorkrecordQueryDto parm) public IActionResult Export([FromQuery] CamWorkrecordQueryDto parm)
{ {
var list = _CamWorkrecordService.ExportList(parm).Result; var list = _CamWorkrecordService.ExportList(parm).Result;
@ -207,7 +207,47 @@ namespace ZR.Admin.WebApi.Controllers.Business
it.ImageUrl = temp; it.ImageUrl = temp;
i++; i++;
}); });
ExcelHelper excelHelper = new ExcelHelper(WebHostEnvironment); ExcelPackage.License.SetNonCommercialPersonal("pnaa");
var result = ExportWorkRecordExcel(list, imagesByRecordId, url, savePath, "工作记录", 100, 70, 60);
// 返回下载URL让浏览器直接下载避免流传输卡死
var downloadUrl = $"/export/{result.fileName}";
return SUCCESS(new { url = downloadUrl, fileName = result.fileName });
}
/// <summary>
/// 导出工作记录(传统流式下载,适用于小数据量)
/// </summary>
[HttpGet("exportStream")]
[ActionPermissionFilter(Permission = "camworkrecord:export")]
public IActionResult ExportStream([FromQuery] CamWorkrecordQueryDto parm)
{
var list = _CamWorkrecordService.ExportList(parm).Result;
if (list == null || list.Count <= 0)
{
return ToResponse(ResultCode.FAIL, "没有要导出的数据");
}
var url = OptionsSetting.Upload.UploadUrl;
string savePath = Path.Combine(WebHostEnvironment.WebRootPath);
var ids = list.Select(x => x.Id).ToList();
var allImages = _CamWorkrecordImageService.GetListByWorkrecordIds(ids);
var imagesByRecordId = allImages.GroupBy(x => x.WorkrecordId)
.ToDictionary(g => g.Key, g => g.OrderBy(x => x.SortOrder).Select(x => x.ImageUrl).ToList());
int i = 1;
list.ForEach(it =>
{
var temp = string.IsNullOrEmpty(it.ImageUrl) ? "" : it.ImageUrl;
if (temp.IndexOf("http") > -1)
{
var image = temp.Replace(url, "");
temp = savePath + image;
}
it.Index = i;
it.ImageUrl = temp;
i++;
});
ExcelPackage.License.SetNonCommercialPersonal("pnaa"); ExcelPackage.License.SetNonCommercialPersonal("pnaa");
var result = ExportWorkRecordExcel(list, imagesByRecordId, url, savePath, "工作记录", 100, 70, 60); var result = ExportWorkRecordExcel(list, imagesByRecordId, url, savePath, "工作记录", 100, 70, 60);
return ExportExcel(result.Item2, result.Item1); return ExportExcel(result.Item2, result.Item1);

View File

@ -17,6 +17,11 @@ namespace ZR.Model.Business.Dto
public string Workrecord { get; set; } public string Workrecord { get; set; }
public DateTime? BeginRecordTime { get; set; } public DateTime? BeginRecordTime { get; set; }
public DateTime? EndRecordTime { get; set; } public DateTime? EndRecordTime { get; set; }
/// <summary>
/// 导出指定ID列表逗号分隔
/// </summary>
public string Ids { get; set; }
} }
/// <summary> /// <summary>

View File

@ -155,6 +155,14 @@ namespace ZR.Service.Business
{ {
var predicate = Expressionable.Create<CamWorkrecord>(); var predicate = Expressionable.Create<CamWorkrecord>();
// 支持按ID列表导出
if (!string.IsNullOrEmpty(parm.Ids))
{
var idList = parm.Ids.Split(',').Select(int.Parse).ToList();
predicate = predicate.And(it => idList.Contains(it.Id));
return predicate; // 按ID导出时忽略其他条件
}
//predicate = predicate.AndIF(parm.BeginRecordTime == null, it => it.RecordTime >= DateTime.Now.ToShortDateString().ParseToDateTime()); //predicate = predicate.AndIF(parm.BeginRecordTime == null, it => it.RecordTime >= DateTime.Now.ToShortDateString().ParseToDateTime());
predicate = predicate.AndIF(parm.BeginRecordTime != null, it => it.RecordTime >= parm.BeginRecordTime); predicate = predicate.AndIF(parm.BeginRecordTime != null, it => it.RecordTime >= parm.BeginRecordTime);
predicate = predicate.AndIF(parm.EndRecordTime != null, it => it.RecordTime <= parm.EndRecordTime); predicate = predicate.AndIF(parm.EndRecordTime != null, it => it.RecordTime <= parm.EndRecordTime);

View File

@ -56,7 +56,16 @@ export function delCamWorkrecord(pid) {
method: 'POST' method: 'POST'
}) })
} }
// 导出工作记录 // 导出工作记录(旧方式,流式下载)
export async function exportCamWorkrecord(query) { export async function exportCamWorkrecord(query) {
await downFile('business/CamWorkrecord/export', { ...query }) await downFile('business/CamWorkrecord/export', { ...query })
} }
// 导出工作记录新方式返回下载URL
export function exportCamWorkrecordUrl(query) {
return request({
url: 'business/CamWorkrecord/export',
method: 'get',
params: query,
})
}

View File

@ -56,6 +56,9 @@
<el-col :span="1.5"> <el-col :span="1.5">
<el-button type="warning" plain icon="download" @click="handleExport" v-hasPermi="['camworkrecord:export']"> 导出 </el-button> <el-button type="warning" plain icon="download" @click="handleExport" v-hasPermi="['camworkrecord:export']"> 导出 </el-button>
</el-col> </el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="download" :disabled="multiple" @click="handleExportSelected" v-hasPermi="['camworkrecord:export']"> 导出所选 </el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList" :columns="columns"></right-toolbar> <right-toolbar v-model:showSearch="showSearch" @queryTable="getList" :columns="columns"></right-toolbar>
</el-row> </el-row>
@ -364,7 +367,7 @@
</template> </template>
<script setup name="camworkrecord"> <script setup name="camworkrecord">
import { listCamWorkrecord, addCamWorkrecord, delCamWorkrecord, updateCamWorkrecord, getCamWorkrecord } from '@/api/business/camworkrecord.js' import { listCamWorkrecord, addCamWorkrecord, delCamWorkrecord, updateCamWorkrecord, getCamWorkrecord, exportCamWorkrecordUrl } from '@/api/business/camworkrecord.js'
import { UploadFilled } from '@element-plus/icons-vue' import { UploadFilled } from '@element-plus/icons-vue'
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
const ids = ref([]) const ids = ref([])
@ -722,7 +725,57 @@ function handleExport() {
type: 'warning' type: 'warning'
}) })
.then(async () => { .then(async () => {
await proxy.downFile('/business/CamWorkrecord/export', { ...queryParams }) const loadingInstance = proxy.$loading({ text: '正在生成导出文件,请稍候...', background: 'rgba(0, 0, 0, 0.7)' })
try {
// URL
const res = await exportCamWorkrecordUrl(queryParams)
if (res.code === 200 && res.data?.url) {
// URL
const downloadUrl = import.meta.env.VITE_APP_BASE_API + res.data.url
window.open(downloadUrl, '_blank')
proxy.$modal.msgSuccess('文件生成成功,正在下载...')
} else {
proxy.$modal.msgError(res.msg || '导出失败')
}
} catch (error) {
console.error('导出失败:', error)
proxy.$modal.msgError('导出失败,请稍后重试')
} finally {
loadingInstance.close()
}
})
}
//
function handleExportSelected() {
if (ids.value.length === 0) {
proxy.$modal.msgWarning('请先选择要导出的数据')
return
}
proxy
.$confirm(`是否确认导出所选的 ${ids.value.length} 条数据?`, '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(async () => {
const loadingInstance = proxy.$loading({ text: '正在生成导出文件,请稍候...', background: 'rgba(0, 0, 0, 0.7)' })
try {
// ID
const res = await exportCamWorkrecordUrl({ ids: ids.value.join(',') })
if (res.code === 200 && res.data?.url) {
const downloadUrl = import.meta.env.VITE_APP_BASE_API + res.data.url
window.open(downloadUrl, '_blank')
proxy.$modal.msgSuccess('文件生成成功,正在下载...')
} else {
proxy.$modal.msgError(res.msg || '导出失败')
}
} catch (error) {
console.error('导出失败:', error)
proxy.$modal.msgError('导出失败,请稍后重试')
} finally {
loadingInstance.close()
}
}) })
} }