Browse Source

update

pull/1/head
wanggang 1 year ago
parent
commit
a0c180b2bb
  1. 9
      docs/demo/src/WTA.Shared/Controllers/GenericController.cs
  2. 126
      docs/demo/src/WTA.Shared/ExportImport/ClosedXmlExportImportService.cs
  3. 2
      docs/demo/src/WTA.Shared/ExportImport/IExportImportService.cs
  4. 2
      docs/demo/src/WTA.Shared/Monitor/MonitorHostedService.cs
  5. 60
      docs/demo/src/WTA/wwwroot/components/list/index.js
  6. 15
      docs/demo/src/WTA/wwwroot/request/index.js
  7. 10
      docs/demo/src/WTA/wwwroot/signalr/index.js

9
docs/demo/src/WTA.Shared/Controllers/GenericController.cs

@ -197,10 +197,17 @@ public class GenericController<TEntity, TModel, TListModel, TSearchModel, TImpor
[Consumes("multipart/form-data")]
[HttpPost, Multiple, Order(-2), HtmlClass("el-button--primary")]
public virtual IActionResult Import([Required] IFormFile importexcelfile, bool partial = false, bool replace = false)
public virtual IActionResult Import([Required] IFormFile file, bool partial = false, bool replace = false)
{
try
{
var exportImportService = this.HttpContext.RequestServices.GetRequiredService<IExportImportService>();
var list = exportImportService.Import<TImportModel>(file.OpenReadStream());
list.ForEach(item =>
{
this.Repository.Insert(item.ToObject<TEntity>());
});
this.Repository.SaveChanges();
return NoContent();
}
catch (Exception ex)

126
docs/demo/src/WTA.Shared/ExportImport/ClosedXmlExportImportService.cs

@ -37,7 +37,7 @@ public class ClosedXmlExportImportService : IExportImportService
var ws = workbook.Worksheets.Add(name);
//
var type = typeof(TExportModel);
var propertyList = GetPropertiesForImportModel(type);
var propertyList = GetProperties(type);
var rowIndex = 1;
for (var i = 0; i < propertyList.Length; i++)
{
@ -53,8 +53,9 @@ public class ClosedXmlExportImportService : IExportImportService
{
var property = propertyList[i];
var columnIndex = i + 1;
var value = property.GetValue(model)?.ToString();
var cell = ws.Cell(rowIndex, columnIndex);
cell.Value = property.GetValue(model)?.ToString();
SetCell(model, cell, property);
}
});
//
@ -81,7 +82,7 @@ public class ClosedXmlExportImportService : IExportImportService
var name = type.GetDisplayName();
var fileName = $"{name}_导入模板.xlsx";
var ws = workbook.Worksheets.Add(name);
var properties = GetPropertiesForImportModel(type);
var properties = GetProperties(type);
for (var i = 0; i < properties.Length; i++)
{
var property = properties[i];
@ -99,15 +100,15 @@ public class ClosedXmlExportImportService : IExportImportService
return result;
}
public IList<TImportModel> Import<TImportModel>(byte[] bytes)
public IList<TImportModel> Import<TImportModel>(Stream stream)
{
try
{
var result = new List<TImportModel>();
//
using var workbook = new XLWorkbook(new MemoryStream(bytes));
using var workbook = new XLWorkbook(stream);
var type = typeof(TImportModel);
var properties = GetPropertiesForImportModel(type).ToDictionary(o => o.GetCustomAttribute<ImporterHeaderAttribute>()?.Name ?? o.GetCustomAttribute<DisplayAttribute>()?.Name ?? o.Name);
var properties = GetProperties(type).ToDictionary(o => o.GetCustomAttribute<ImporterHeaderAttribute>()?.Name ?? o.GetDisplayName() ?? o.Name);
var name = type.GetCustomAttribute<DisplayAttribute>()?.Name ?? typeof(TImportModel).Name;
var ws = workbook.Worksheets.FirstOrDefault();
if (ws != null)
@ -121,40 +122,12 @@ public class ClosedXmlExportImportService : IExportImportService
{
var columnIndex = j + 1;
var cell = row.Cell(columnIndex);
var value = cell.Value;
if (value.ToString() != "")
var headerName = ws.Cell(1, columnIndex).Value.ToString().Trim();
var value = cell.Value.ToString().Trim();
if (!string.IsNullOrEmpty(value) && properties.TryGetValue(headerName, out var property))
{
var headerName = ws.Cell(1, columnIndex).Value.ToString().Trim();
properties.TryGetValue(headerName, out var property);
if (property != null)
{
var propertyType = property.PropertyType;
if (propertyType.IsEnum)
{
var enumValue = Enum.GetNames(propertyType)
.Select(o => new KeyValuePair<string, Enum>(o, (Enum)Enum.Parse(propertyType, o)))
.Where(o => o.Value.GetDisplayName() == value.ToString())
.Select(o => o.Value)
.FirstOrDefault();
property.SetValue(model, enumValue);
}
else if (propertyType.Name == nameof(Boolean))
{
if (value.GetText() == "是")
{
property.SetValue(model, true);
}
else
{
property.SetValue(model, false);
}
}
else
{
var propertyValue = Convert.ChangeType(value.ToString(), propertyType, CultureInfo.InvariantCulture);
property.SetValue(model, propertyValue);
}
}
SetProperty(model, property, value);
}
}
result.Add(model);
@ -169,10 +142,79 @@ public class ClosedXmlExportImportService : IExportImportService
}
}
private static PropertyInfo[] GetPropertiesForImportModel(Type type)
private static PropertyInfo[] GetProperties(Type type)
{
return type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty)
.Where(o => o.GetCustomAttribute<ImporterHeaderAttribute>(true) == null || !o.GetCustomAttribute<ImporterHeaderAttribute>()!.IsIgnore)
var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty);
return properties
.Where(o => o.PropertyType == typeof(string) || o.PropertyType.IsNullableType() || o.PropertyType.IsValueType)
.Where(o => !o.GetCustomAttributes<ScaffoldColumnAttribute>(true).Any())
.Where(o => !o.GetCustomAttributes<ImporterHeaderAttribute>(true).Any() || !o.GetCustomAttribute<ImporterHeaderAttribute>(true)!.IsIgnore)
.ToArray();
}
/// <summary>
/// 导出设置单元格
/// </summary>
private static void SetCell<TExportModel>(TExportModel? model, IXLCell cell, PropertyInfo property)
{
var propertyType = property.PropertyType.GetUnderlyingType();
var value = property.GetValue(model)?.ToString()?.Trim();
if (string.IsNullOrEmpty(value))
{
return;
}
if (propertyType == typeof(bool))
{
cell.Value = (bool)property.GetValue(model)! ? "是" : "否";
}
else if (propertyType.IsEnum)
{
cell.Value = (Enum.Parse(propertyType, value) as Enum)?.GetDisplayName();
}
else if (propertyType == typeof(DateTime))
{
cell.Value = ((DateTime)property.GetValue(model)!).ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture);
}
else
{
cell.Value = value;
}
}
/// <summary>
/// 导入设置属性值
/// </summary>
private static void SetProperty<TImopotModel>(TImopotModel model, PropertyInfo property, string value)
{
var propertyType = property.PropertyType.GetUnderlyingType();
if (propertyType.IsEnum)
{
var enumValue = Enum.GetNames(propertyType)
.Select(o => new KeyValuePair<string, Enum>(o, (Enum)Enum.Parse(propertyType, o)))
.Where(o => o.Value.GetDisplayName() == value.ToString())
.Select(o => o.Value)
.FirstOrDefault();
property.SetValue(model, enumValue);
}
else if (propertyType == typeof(bool))
{
if (value == "是")
{
property.SetValue(model, true);
}
else
{
property.SetValue(model, false);
}
}
else if (propertyType == typeof(Guid))
{
property.SetValue(model, Guid.Parse(value));
}
else
{
var propertyValue = Convert.ChangeType(value.ToString(), propertyType, CultureInfo.InvariantCulture);
property.SetValue(model, propertyValue);
}
}
}

2
docs/demo/src/WTA.Shared/ExportImport/IExportImportService.cs

@ -8,5 +8,5 @@ public interface IExportImportService
FileContentResult GetImportTemplate<TImportModel>();
IList<TImportModel> Import<TImportModel>(byte[] bytes);
IList<TImportModel> Import<TImportModel>(Stream stream);
}

2
docs/demo/src/WTA.Shared/Monitor/MonitorHostedService.cs

@ -34,7 +34,7 @@ public class MonitorHostedService : IHostedService
{
Debug.WriteLine(ex.ToString());
}
await Task.Delay(1000 * 1).ConfigureAwait(false);
await Task.Delay(5000 * 1).ConfigureAwait(false);
}
}, cancellationToken);
return Task.CompletedTask;

60
docs/demo/src/WTA/wwwroot/components/list/index.js

@ -194,7 +194,7 @@ export default {
v-model="dialogVisible"
align-center
destroy-on-close
style="width:auto;min-width:300px;max-width:700px;"
style="width:auto;min-width:500px;max-width:1000px;"
>
<template #header> <span class="el-dialog__title"> {{editFormTitle}} </span> </template>
<el-row v-loading="editFormloading">
@ -214,7 +214,7 @@ export default {
/>
</template>
<template v-else-if="editFormMode==='export'">
<el-form :model="exportModel" style="height:100%;">
<el-form :model="exportModel">
<el-form-item :label="$t('全部')">
<el-switch v-model="exportModel.includeAll" />
</el-form-item>
@ -224,9 +224,9 @@ export default {
</el-form>
</template>
<template v-else-if="editFormMode==='import'">
<el-form :model="importModel" style="height:100%;">
<el-form :model="importModel" inline>
<el-form-item :label="$t('部分成功')">
<el-switch v-model="importModel.partal" />
<el-switch v-model="importModel.partial" />
</el-form-item>
<el-form-item :label="$t('全部替换')">
<el-switch v-model="importModel.replace" />
@ -235,9 +235,17 @@ export default {
<el-link type="primary" @click="getImportTemplate">{{$t('下载')}}</el-link>
</el-form-item>
<el-form-item :label="$t('文件')">
<el-upload drag v-model="importModel.file" :auto-upload="false">
<el-upload
ref="uploadRef"
drag
accept=".xlsx"
:disabled="fileList.length===1"
:limit="1"
:auto-upload="false"
:on-change="handleChange"
>
<el-icon class="el-icon--upload"><ep-upload-filled /></el-icon>
<div class="el-upload__text">{{$t('拖放文件到此处或')}} <em>{{$t('点击上传')}}</em></div>
<div class="el-upload__text">{{$t('拖放文件或')}} <em>{{$t('点击上传')}}</em></div>
</el-upload>
</el-form-item>
</el-form>
@ -320,6 +328,7 @@ export default {
children: "children",
});
const tableRef = ref(null);
const uploadRef = ref(null);
const columns = ref([]);
const filterDrawer = ref(false);
const subDrawer = ref(false);
@ -353,9 +362,8 @@ export default {
const importModel = reactive({
partial: true,
replace: false,
template: null,
file: null,
});
const fileList = ref([]);
const getSortModel = (model) => {
model.orderBy
.split(",")
@ -466,6 +474,7 @@ export default {
//import
const url = `${baseUrl}/${item.path}`;
editFormTitle.value = `${t(item.path)}${schema.value?.title}`;
fileList.value = [];
dialogVisible.value = true;
} else if (item === "filter") {
editFormTitle.value = t("自定义查询");
@ -504,14 +513,20 @@ export default {
delete postData.query["id"];
const url = `${baseUrl}/${editFormMode.value}?${qs.stringify(exportModel)}`;
const response = await post(url, postData);
const downloadUrl = window.URL.createObjectURL(response.data);
const filename = response.filename;
let link = document.createElement("a");
link.href = downloadUrl;
link.download = filename;
link.click();
window.URL.revokeObjectURL(downloadUrl);
download(response);
dialogVisible.value = false;
} else if (editFormMode.value === "import") {
editFormloading.value = true;
const url = `${baseUrl}/${editFormMode.value}`;
const formData = new FormData();
formData.append("partial", importModel.partial);
formData.append("replace", importModel.replace);
formData.append("file", fileList.value[0]?.raw);
console.log(uploadRef.value);
const response = await post(url, formData);
editFormloading.value = false;
dialogVisible.value = false;
await load(indexUrl);
} else if (editFormMode.value === "filter") {
await load(indexUrl);
dialogVisible.value = false;
@ -547,9 +562,7 @@ export default {
logic: "and",
});
};
const getImportTemplate = async () => {
const url = `${baseUrl}/${editFormMode.value}`;
const response = await get(url);
const download = (response) => {
const downloadUrl = window.URL.createObjectURL(response.data);
const filename = response.filename;
let link = document.createElement("a");
@ -558,6 +571,14 @@ export default {
link.click();
window.URL.revokeObjectURL(downloadUrl);
};
const getImportTemplate = async () => {
const url = `${baseUrl}/${editFormMode.value}`;
const response = await get(url);
download(response);
};
const handleChange = (uploadFile, uploadFiles) => {
fileList.value = uploadFiles;
};
onMounted(async () => {
pushQueryList();
const vm = (await get(indexUrl)).data;
@ -575,6 +596,7 @@ export default {
return {
treeProps,
tableRef,
uploadRef,
tableLoading,
columns,
showColumn,
@ -609,6 +631,8 @@ export default {
showList,
subListQuery,
pushQueryList,
fileList,
handleChange,
};
},
};

15
docs/demo/src/WTA/wwwroot/request/index.js

@ -78,20 +78,23 @@ const get = async (url, data, options, withoutToken = false, withoutCulture = fa
const post = async (url, data, options, withoutToken = false, withoutCulture = false) => {
url = getUrl(url, withoutCulture);
const defaultOptions = {
let defaultOptions = {
method: "POST",
headers: {
"Content-Type": "application/json",
},
headers: {},
};
if (!(data instanceof FormData)) {
defaultOptions.headers["Content-Type"] = "application/json";
}
if (options) {
Object.assign(defaultOptions, options);
}
if (data && !defaultOptions.body) {
if (defaultOptions.headers["Content-Type"] === "application/x-www-form-urlencoded") {
if (defaultOptions.headers["Content-Type"]?.startsWith("application/x-www-form-urlencoded")) {
defaultOptions.body = qs.stringify(data);
} else {
} else if (defaultOptions.headers["Content-Type"]?.startsWith("application/json")) {
defaultOptions.body = JSON.stringify(data);
} else {
defaultOptions.body = data;
}
}
if (!withoutToken) {

10
docs/demo/src/WTA/wwwroot/signalr/index.js

@ -7,11 +7,10 @@ let connectionId = null;
const connection = new signalR.HubConnectionBuilder()
.withUrl("./api/hub", {
accessTokenFactory: () => {
const appStore = useAppStore();
return appStore.token;
return useAppStore().token;
},
})
.withAutomaticReconnect()
//.withAutomaticReconnect()
.build();
const connect = async () => {
if (await isLogin()) {
@ -21,9 +20,10 @@ const connect = async () => {
.then(function () {
console.log("signalr connected");
})
.catch(function (error) {
.catch(async function (error) {
console.log(error);
//setTimeout(connect, 5000);
await isLogin();
setTimeout(connect, 5000);
});
}
}

Loading…
Cancel
Save