This commit is contained in:
parent
a32354f941
commit
a6c639dd43
|
|
@ -138,6 +138,7 @@
|
||||||
import { ref, reactive, getCurrentInstance, nextTick } from 'vue'
|
import { ref, reactive, getCurrentInstance, nextTick } from 'vue'
|
||||||
import { onLoad } from '@dcloudio/uni-app'
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
import { addFault } from '@/services/trunk'
|
import { addFault } from '@/services/trunk'
|
||||||
|
import { getPresignUrls, uploadToCos } from '@/services/cos'
|
||||||
import { addWatermark } from '@/utils/watermark'
|
import { addWatermark } from '@/utils/watermark'
|
||||||
|
|
||||||
const statusBarHeight = uni.getSystemInfoSync().statusBarHeight || 0
|
const statusBarHeight = uni.getSystemInfoSync().statusBarHeight || 0
|
||||||
|
|
@ -311,10 +312,10 @@ async function handleSubmit() {
|
||||||
|
|
||||||
if (submitting.value) return
|
if (submitting.value) return
|
||||||
submitting.value = true
|
submitting.value = true
|
||||||
uni.showLoading({ title: '提交中...', mask: true })
|
uni.showLoading({ title: '处理图片中...', mask: true })
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 水印处理
|
// 1. 水印处理
|
||||||
const watermarkLines = [
|
const watermarkLines = [
|
||||||
`${form.faultTime} ${form.personnel}`,
|
`${form.faultTime} ${form.personnel}`,
|
||||||
`故障原因:${form.faultReason || ''}`,
|
`故障原因:${form.faultReason || ''}`,
|
||||||
|
|
@ -332,35 +333,39 @@ async function handleSubmit() {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
watermarkedPhotos.push(result)
|
watermarkedPhotos.push(result)
|
||||||
// 每张图处理完后等一下,让 canvas 状态重置
|
|
||||||
await nextTick()
|
await nextTick()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
watermarkedPhotos.push(photo)
|
watermarkedPhotos.push(photo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 构建上传数据
|
// 2. 获取 COS 预签名 URL
|
||||||
const files = watermarkedPhotos.map((path, index) => ({
|
uni.showLoading({ title: '准备上传...', mask: true })
|
||||||
name: 'images',
|
const presignList = await getPresignUrls(watermarkedPhotos.length, '.jpg')
|
||||||
uri: path
|
|
||||||
}))
|
|
||||||
|
|
||||||
const formData = {
|
// 3. 逐张直传到 COS
|
||||||
files,
|
const imageUrls = []
|
||||||
data: {
|
for (let i = 0; i < watermarkedPhotos.length; i++) {
|
||||||
cableId: cableId.value,
|
uni.showLoading({ title: `上传图片 ${i + 1}/${watermarkedPhotos.length}`, mask: true })
|
||||||
faultTime: form.faultTime,
|
await uploadToCos(presignList[i].presignUrl, watermarkedPhotos[i])
|
||||||
personnel: form.personnel,
|
imageUrls.push(presignList[i].accessUrl)
|
||||||
faultReason: form.faultReason,
|
|
||||||
mileage: form.mileage,
|
|
||||||
mileageCorrection: form.mileageCorrection,
|
|
||||||
latitude: String(form.latitude),
|
|
||||||
longitude: String(form.longitude),
|
|
||||||
remark: form.remark
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await addFault(formData)
|
// 4. 提交故障表单(JSON)
|
||||||
|
uni.showLoading({ title: '提交中...', mask: true })
|
||||||
|
const res = await addFault({
|
||||||
|
cableId: Number(cableId.value),
|
||||||
|
faultTime: form.faultTime,
|
||||||
|
personnel: form.personnel,
|
||||||
|
faultReason: form.faultReason,
|
||||||
|
mileage: form.mileage,
|
||||||
|
mileageCorrection: form.mileageCorrection,
|
||||||
|
latitude: Number(form.latitude),
|
||||||
|
longitude: Number(form.longitude),
|
||||||
|
remark: form.remark,
|
||||||
|
imageUrls
|
||||||
|
})
|
||||||
|
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
uni.showToast({ title: '提交成功', icon: 'success' })
|
uni.showToast({ title: '提交成功', icon: 'success' })
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|
@ -370,7 +375,8 @@ async function handleSubmit() {
|
||||||
uni.showToast({ title: res.msg || '提交失败', icon: 'none' })
|
uni.showToast({ title: res.msg || '提交失败', icon: 'none' })
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
uni.showToast({ title: '网络异常,请重试', icon: 'none' })
|
console.error('[fault-add] 提交失败:', err)
|
||||||
|
uni.showToast({ title: err.message || '网络异常,请重试', icon: 'none' })
|
||||||
} finally {
|
} finally {
|
||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
submitting.value = false
|
submitting.value = false
|
||||||
|
|
|
||||||
93
odf-uniapp/services/cos.js
Normal file
93
odf-uniapp/services/cos.js
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
import { post } from './api'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从后端获取 COS 预签名上传 URL
|
||||||
|
* @param {number} count - 文件数量
|
||||||
|
* @param {string} ext - 文件扩展名
|
||||||
|
* @returns {Promise<Array<{cosKey, presignUrl, accessUrl}>>}
|
||||||
|
*/
|
||||||
|
export async function getPresignUrls(count, ext = '.jpg') {
|
||||||
|
const res = await post('/business/CosUpload/presignUrl', { count, ext })
|
||||||
|
if (res.code !== 200) {
|
||||||
|
throw new Error(res.msg || '获取上传地址失败')
|
||||||
|
}
|
||||||
|
return res.data
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过预签名 URL 直传文件到 COS
|
||||||
|
* @param {string} presignUrl - PUT 预签名 URL
|
||||||
|
* @param {string} filePath - 本地文件路径
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
export function uploadToCos(presignUrl, filePath) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
// #ifdef H5
|
||||||
|
_uploadH5(presignUrl, filePath).then(resolve).catch(reject)
|
||||||
|
// #endif
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
_uploadApp(presignUrl, filePath).then(resolve).catch(reject)
|
||||||
|
// #endif
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// #ifdef H5
|
||||||
|
async function _uploadH5(presignUrl, filePath) {
|
||||||
|
// H5 端 filePath 可能是 base64 或 blob URL
|
||||||
|
let blob
|
||||||
|
if (filePath.startsWith('data:')) {
|
||||||
|
const resp = await fetch(filePath)
|
||||||
|
blob = await resp.blob()
|
||||||
|
} else {
|
||||||
|
const resp = await fetch(filePath)
|
||||||
|
blob = await resp.blob()
|
||||||
|
}
|
||||||
|
const res = await fetch(presignUrl, {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: { 'Content-Type': 'image/jpeg' },
|
||||||
|
body: blob
|
||||||
|
})
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error(`COS上传失败: ${res.status}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
function _uploadApp(presignUrl, filePath) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
plus.io.resolveLocalFileSystemURL(filePath, (entry) => {
|
||||||
|
entry.file((file) => {
|
||||||
|
const reader = new plus.io.FileReader()
|
||||||
|
reader.onloadend = (e) => {
|
||||||
|
const base64 = e.target.result
|
||||||
|
// 将 base64 转为 ArrayBuffer
|
||||||
|
const binary = atob(base64.split(',')[1])
|
||||||
|
const len = binary.length
|
||||||
|
const bytes = new Uint8Array(len)
|
||||||
|
for (let i = 0; i < len; i++) {
|
||||||
|
bytes[i] = binary.charCodeAt(i)
|
||||||
|
}
|
||||||
|
// 使用 XMLHttpRequest 发送 PUT
|
||||||
|
const xhr = new XMLHttpRequest()
|
||||||
|
xhr.open('PUT', presignUrl, true)
|
||||||
|
xhr.setRequestHeader('Content-Type', 'image/jpeg')
|
||||||
|
xhr.onload = () => {
|
||||||
|
if (xhr.status >= 200 && xhr.status < 300) {
|
||||||
|
resolve()
|
||||||
|
} else {
|
||||||
|
reject(new Error(`COS上传失败: ${xhr.status}`))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xhr.onerror = () => reject(new Error('COS上传网络错误'))
|
||||||
|
xhr.send(bytes.buffer)
|
||||||
|
}
|
||||||
|
reader.onerror = () => reject(new Error('读取文件失败'))
|
||||||
|
reader.readAsDataURL(file)
|
||||||
|
})
|
||||||
|
}, (err) => {
|
||||||
|
reject(new Error('解析文件路径失败: ' + JSON.stringify(err)))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import { get, post, BASE_URL } from './api'
|
import { get, post } from './api'
|
||||||
import store from '@/store'
|
|
||||||
|
|
||||||
export const getCableList = (deptId) =>
|
export const getCableList = (deptId) =>
|
||||||
get('/business/OdfCables/list', { deptId })
|
get('/business/OdfCables/list', { deptId })
|
||||||
|
|
@ -11,36 +10,11 @@ export const getFaultDetail = (id) =>
|
||||||
get(`/business/OdfCableFaults/${id}`)
|
get(`/business/OdfCableFaults/${id}`)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 新增故障(multipart/form-data,含图片上传)
|
* 新增故障(JSON 提交,图片已上传至 COS)
|
||||||
* @param {FormData|object} formData - 包含故障信息和图片的 FormData
|
* @param {object} data - 故障信息,含 imageUrls 数组
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
export function addFault(formData) {
|
export const addFault = (data) => post('/business/OdfCableFaults/add', data)
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const header = {
|
|
||||||
'Authorization': `Bearer ${store.token}`,
|
|
||||||
'Userid': store.userId,
|
|
||||||
'Username': store.userName
|
|
||||||
}
|
|
||||||
uni.uploadFile({
|
|
||||||
url: BASE_URL + '/business/OdfCableFaults/add',
|
|
||||||
files: formData.files || [],
|
|
||||||
formData: formData.data || {},
|
|
||||||
header,
|
|
||||||
success(res) {
|
|
||||||
try {
|
|
||||||
const result = JSON.parse(res.data)
|
|
||||||
resolve({ code: result.code, msg: result.msg, data: result.data })
|
|
||||||
} catch (e) {
|
|
||||||
reject({ code: -1, msg: '解析响应失败' })
|
|
||||||
}
|
|
||||||
},
|
|
||||||
fail(err) {
|
|
||||||
reject({ code: -1, msg: err.errMsg || '网络异常' })
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export const incrementFaultCount = (id) =>
|
export const incrementFaultCount = (id) =>
|
||||||
post(`/business/OdfCableFaults/incrementFaultCount/${id}`)
|
post(`/business/OdfCableFaults/incrementFaultCount/${id}`)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,90 @@
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using COSXML;
|
||||||
|
using COSXML.Auth;
|
||||||
|
using COSXML.Model.Tag;
|
||||||
|
|
||||||
|
namespace ZR.Admin.WebApi.Controllers.Business
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// COS 预签名上传
|
||||||
|
/// </summary>
|
||||||
|
[Route("business/CosUpload")]
|
||||||
|
public class CosUploadController : BaseController
|
||||||
|
{
|
||||||
|
private readonly IConfiguration _config;
|
||||||
|
|
||||||
|
public CosUploadController(IConfiguration config)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取 COS PUT 预签名 URL(前端直传)
|
||||||
|
/// </summary>
|
||||||
|
[HttpPost("presignUrl")]
|
||||||
|
public IActionResult GetPresignUrl([FromBody] CosPresignRequestDto dto)
|
||||||
|
{
|
||||||
|
var section = _config.GetSection("TencentCos");
|
||||||
|
var appId = section["AppId"];
|
||||||
|
var bucket = section["Bucket"];
|
||||||
|
var region = section["Region"];
|
||||||
|
var secretId = section["SecretId"];
|
||||||
|
var secretKey = section["SecretKey"];
|
||||||
|
var domainUrl = section["DomainUrl"];
|
||||||
|
var expireMinutes = int.Parse(section["PresignExpireMinutes"] ?? "10");
|
||||||
|
|
||||||
|
int count = Math.Clamp(dto.Count, 1, 9);
|
||||||
|
string ext = string.IsNullOrWhiteSpace(dto.Ext) ? ".jpg" : dto.Ext;
|
||||||
|
|
||||||
|
var cosConfig = new CosXmlConfig.Builder()
|
||||||
|
.SetRegion(region)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var credentialProvider = new DefaultQCloudCredentialProvider(
|
||||||
|
secretId, secretKey, (long)expireMinutes * 60);
|
||||||
|
var cosXml = new CosXmlServer(cosConfig, credentialProvider);
|
||||||
|
|
||||||
|
var results = new List<object>();
|
||||||
|
var dateDir = DateTime.Now.ToString("yyyyMMdd");
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
var cosKey = $"fault-images/{dateDir}/{Guid.NewGuid():N}{ext}";
|
||||||
|
|
||||||
|
var preSignatureStruct = new PreSignatureStruct
|
||||||
|
{
|
||||||
|
appid = appId,
|
||||||
|
bucket = bucket,
|
||||||
|
region = region,
|
||||||
|
key = cosKey,
|
||||||
|
httpMethod = "PUT",
|
||||||
|
isHttps = true,
|
||||||
|
signDurationSecond = expireMinutes * 60,
|
||||||
|
headers = null,
|
||||||
|
queryParameters = null
|
||||||
|
};
|
||||||
|
|
||||||
|
var presignUrl = cosXml.GenerateSignURL(preSignatureStruct);
|
||||||
|
var accessUrl = $"{domainUrl.TrimEnd('/')}/{cosKey}";
|
||||||
|
|
||||||
|
results.Add(new { cosKey, presignUrl, accessUrl });
|
||||||
|
}
|
||||||
|
|
||||||
|
return SUCCESS(results);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CosPresignRequestDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 需要上传的文件数量
|
||||||
|
/// </summary>
|
||||||
|
public int Count { get; set; } = 1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 文件扩展名,如 .jpg
|
||||||
|
/// </summary>
|
||||||
|
public string Ext { get; set; } = ".jpg";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -49,13 +49,13 @@ namespace ZR.Admin.WebApi.Controllers.Business
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 新增故障(含图片上传,APP端调用)
|
/// 新增故障(图片已上传至COS,提交COS URL)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[HttpPost("add")]
|
[HttpPost("add")]
|
||||||
[ActionPermissionFilter(Permission = "odfcablefaults:list")]
|
[ActionPermissionFilter(Permission = "odfcablefaults:list")]
|
||||||
[Log(Title = "干线故障", BusinessType = BusinessType.INSERT)]
|
[Log(Title = "干线故障", BusinessType = BusinessType.INSERT)]
|
||||||
public async Task<IActionResult> Add([FromForm] OdfCableFaultAddDto dto)
|
public async Task<IActionResult> Add([FromBody] OdfCableFaultAddDto dto)
|
||||||
{
|
{
|
||||||
dto.UserId = HttpContext.GetUId();
|
dto.UserId = HttpContext.GetUId();
|
||||||
var response = await _OdfCableFaultsService.AddFault(dto);
|
var response = await _OdfCableFaultsService.AddFault(dto);
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="7.0.12" />
|
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="7.0.12" />
|
||||||
<PackageReference Include="NLog.Web.AspNetCore" Version="5.4.0" />
|
<PackageReference Include="NLog.Web.AspNetCore" Version="5.4.0" />
|
||||||
<PackageReference Include="Mapster" Version="7.4.0" />
|
<PackageReference Include="Mapster" Version="7.4.0" />
|
||||||
|
<PackageReference Include="Tencent.QCloud.Cos.Sdk" Version="5.4.44" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,16 @@
|
||||||
"notAllowedExt": [ ".bat", ".exe", ".jar", ".js" ],
|
"notAllowedExt": [ ".bat", ".exe", ".jar", ".js" ],
|
||||||
"requestLimitSize": 50 //请求body大小限制
|
"requestLimitSize": 50 //请求body大小限制
|
||||||
},
|
},
|
||||||
|
// 腾讯云COS配置
|
||||||
|
"TencentCos": {
|
||||||
|
"AppId": "1308826010",
|
||||||
|
"Bucket": "youdas-1308826010",
|
||||||
|
"Region": "ap-shanghai",
|
||||||
|
"SecretId": "AKIDNdjgTFyZ3UmvsdDbpsiNp690e6MPFrHV",
|
||||||
|
"SecretKey": "5xc6PVWM0SggYEguxyxkS5bvgNr8B0c2",
|
||||||
|
"DomainUrl": "https://youdas-1308826010.cos.ap-shanghai.myqcloud.com",
|
||||||
|
"PresignExpireMinutes": 10
|
||||||
|
},
|
||||||
//阿里云存储配置
|
//阿里云存储配置
|
||||||
"ALIYUN_OSS": {
|
"ALIYUN_OSS": {
|
||||||
"REGIONID": "https://oss-cn-shanghai.aliyuncs.com", //eg:cn-hangzhou
|
"REGIONID": "https://oss-cn-shanghai.aliyuncs.com", //eg:cn-hangzhou
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using MiniExcelLibs.Attributes;
|
using MiniExcelLibs.Attributes;
|
||||||
|
|
||||||
namespace ZR.Model.Business.Dto
|
namespace ZR.Model.Business.Dto
|
||||||
|
|
@ -50,7 +49,10 @@ namespace ZR.Model.Business.Dto
|
||||||
|
|
||||||
public long? UserId { get; set; }
|
public long? UserId { get; set; }
|
||||||
|
|
||||||
public IFormFile[] Images { get; set; }
|
/// <summary>
|
||||||
|
/// COS 图片访问 URL 列表(前端直传 COS 后传入)
|
||||||
|
/// </summary>
|
||||||
|
public string[] ImageUrls { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
using Infrastructure;
|
using Infrastructure;
|
||||||
using Infrastructure.Attribute;
|
using Infrastructure.Attribute;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using ZR.Model;
|
using ZR.Model;
|
||||||
using ZR.Model.Business;
|
using ZR.Model.Business;
|
||||||
using ZR.Model.Business.Dto;
|
using ZR.Model.Business.Dto;
|
||||||
|
|
@ -156,7 +154,7 @@ namespace ZR.Service.Business
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 新增故障(含图片上传)
|
/// 新增故障(图片已上传至 COS,仅保存 URL)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task<int> AddFault(OdfCableFaultAddDto dto)
|
public async Task<int> AddFault(OdfCableFaultAddDto dto)
|
||||||
{
|
{
|
||||||
|
|
@ -170,7 +168,7 @@ namespace ZR.Service.Business
|
||||||
}
|
}
|
||||||
|
|
||||||
// 校验至少 1 张图片
|
// 校验至少 1 张图片
|
||||||
if (dto.Images == null || dto.Images.Length == 0)
|
if (dto.ImageUrls == null || dto.ImageUrls.Length == 0)
|
||||||
{
|
{
|
||||||
throw new CustomException("请至少上传一张图片");
|
throw new CustomException("请至少上传一张图片");
|
||||||
}
|
}
|
||||||
|
|
@ -196,36 +194,10 @@ namespace ZR.Service.Business
|
||||||
var faultEntity = Insertable(model).ExecuteReturnEntity();
|
var faultEntity = Insertable(model).ExecuteReturnEntity();
|
||||||
int faultId = faultEntity.Id;
|
int faultId = faultEntity.Id;
|
||||||
|
|
||||||
// 保存图片文件并插入图片记录
|
// 插入图片记录(COS URL)
|
||||||
IWebHostEnvironment webHostEnvironment = App.WebHostEnvironment;
|
foreach (var imageUrl in dto.ImageUrls)
|
||||||
string webRootPath = webHostEnvironment.WebRootPath;
|
|
||||||
string uploadDir = Path.Combine("uploads", "fault");
|
|
||||||
string fullDir = Path.Combine(webRootPath, uploadDir);
|
|
||||||
|
|
||||||
if (!Directory.Exists(fullDir))
|
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(fullDir);
|
if (string.IsNullOrWhiteSpace(imageUrl)) continue;
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var image in dto.Images)
|
|
||||||
{
|
|
||||||
string fileExt = Path.GetExtension(image.FileName);
|
|
||||||
string fileName = $"{DateTime.Now:yyyyMMdd}_{Guid.NewGuid():N}{fileExt}";
|
|
||||||
string filePath = Path.Combine(fullDir, fileName);
|
|
||||||
|
|
||||||
using (var stream = new FileStream(filePath, FileMode.Create))
|
|
||||||
{
|
|
||||||
await image.CopyToAsync(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
string imageUrl = $"/{uploadDir}/{fileName}".Replace("\\", "/");
|
|
||||||
|
|
||||||
// 拼接完整URL,前端可直接使用
|
|
||||||
var request = App.HttpContext?.Request;
|
|
||||||
if (request != null)
|
|
||||||
{
|
|
||||||
imageUrl = $"{request.Scheme}://{request.Host}{imageUrl}";
|
|
||||||
}
|
|
||||||
|
|
||||||
var imageRecord = new OdfCableFaultImages
|
var imageRecord = new OdfCableFaultImages
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user