Browse Source

update

pull/1/head
wanggang 1 year ago
parent
commit
a0c180b2bb
  1. 9
      docs/demo/src/WTA.Shared/Controllers/GenericController.cs
  2. 110
      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")] [Consumes("multipart/form-data")]
[HttpPost, Multiple, Order(-2), HtmlClass("el-button--primary")] [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 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(); return NoContent();
} }
catch (Exception ex) catch (Exception ex)

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

@ -37,7 +37,7 @@ public class ClosedXmlExportImportService : IExportImportService
var ws = workbook.Worksheets.Add(name); var ws = workbook.Worksheets.Add(name);
// //
var type = typeof(TExportModel); var type = typeof(TExportModel);
var propertyList = GetPropertiesForImportModel(type); var propertyList = GetProperties(type);
var rowIndex = 1; var rowIndex = 1;
for (var i = 0; i < propertyList.Length; i++) for (var i = 0; i < propertyList.Length; i++)
{ {
@ -53,8 +53,9 @@ public class ClosedXmlExportImportService : IExportImportService
{ {
var property = propertyList[i]; var property = propertyList[i];
var columnIndex = i + 1; var columnIndex = i + 1;
var value = property.GetValue(model)?.ToString();
var cell = ws.Cell(rowIndex, columnIndex); 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 name = type.GetDisplayName();
var fileName = $"{name}_导入模板.xlsx"; var fileName = $"{name}_导入模板.xlsx";
var ws = workbook.Worksheets.Add(name); var ws = workbook.Worksheets.Add(name);
var properties = GetPropertiesForImportModel(type); var properties = GetProperties(type);
for (var i = 0; i < properties.Length; i++) for (var i = 0; i < properties.Length; i++)
{ {
var property = properties[i]; var property = properties[i];
@ -99,15 +100,15 @@ public class ClosedXmlExportImportService : IExportImportService
return result; return result;
} }
public IList<TImportModel> Import<TImportModel>(byte[] bytes) public IList<TImportModel> Import<TImportModel>(Stream stream)
{ {
try try
{ {
var result = new List<TImportModel>(); var result = new List<TImportModel>();
// //
using var workbook = new XLWorkbook(new MemoryStream(bytes)); using var workbook = new XLWorkbook(stream);
var type = typeof(TImportModel); 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 name = type.GetCustomAttribute<DisplayAttribute>()?.Name ?? typeof(TImportModel).Name;
var ws = workbook.Worksheets.FirstOrDefault(); var ws = workbook.Worksheets.FirstOrDefault();
if (ws != null) if (ws != null)
@ -121,14 +122,71 @@ public class ClosedXmlExportImportService : IExportImportService
{ {
var columnIndex = j + 1; var columnIndex = j + 1;
var cell = row.Cell(columnIndex); var cell = row.Cell(columnIndex);
var value = cell.Value;
if (value.ToString() != "")
{
var headerName = ws.Cell(1, columnIndex).Value.ToString().Trim(); var headerName = ws.Cell(1, columnIndex).Value.ToString().Trim();
properties.TryGetValue(headerName, out var property);
if (property != null) var value = cell.Value.ToString().Trim();
if (!string.IsNullOrEmpty(value) && properties.TryGetValue(headerName, out var property))
{
SetProperty(model, property, value);
}
}
result.Add(model);
}
}
return result;
}
catch (Exception ex)
{
this._logger.LogError(ex, ex.ToString());
throw new Exception($"导入数据错误:{ex.Message}", ex);
}
}
private static PropertyInfo[] GetProperties(Type type)
{
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; var propertyType = property.PropertyType.GetUnderlyingType();
if (propertyType.IsEnum) if (propertyType.IsEnum)
{ {
var enumValue = Enum.GetNames(propertyType) var enumValue = Enum.GetNames(propertyType)
@ -138,9 +196,9 @@ public class ClosedXmlExportImportService : IExportImportService
.FirstOrDefault(); .FirstOrDefault();
property.SetValue(model, enumValue); property.SetValue(model, enumValue);
} }
else if (propertyType.Name == nameof(Boolean)) else if (propertyType == typeof(bool))
{ {
if (value.GetText() == "是") if (value == "是")
{ {
property.SetValue(model, true); property.SetValue(model, true);
} }
@ -149,6 +207,10 @@ public class ClosedXmlExportImportService : IExportImportService
property.SetValue(model, false); property.SetValue(model, false);
} }
} }
else if (propertyType == typeof(Guid))
{
property.SetValue(model, Guid.Parse(value));
}
else else
{ {
var propertyValue = Convert.ChangeType(value.ToString(), propertyType, CultureInfo.InvariantCulture); var propertyValue = Convert.ChangeType(value.ToString(), propertyType, CultureInfo.InvariantCulture);
@ -156,23 +218,3 @@ public class ClosedXmlExportImportService : IExportImportService
} }
} }
} }
}
result.Add(model);
}
}
return result;
}
catch (Exception ex)
{
this._logger.LogError(ex, ex.ToString());
throw new Exception($"导入数据错误:{ex.Message}", ex);
}
}
private static PropertyInfo[] GetPropertiesForImportModel(Type type)
{
return type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty)
.Where(o => o.GetCustomAttribute<ImporterHeaderAttribute>(true) == null || !o.GetCustomAttribute<ImporterHeaderAttribute>()!.IsIgnore)
.ToArray();
}
}

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

@ -8,5 +8,5 @@ public interface IExportImportService
FileContentResult GetImportTemplate<TImportModel>(); 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()); Debug.WriteLine(ex.ToString());
} }
await Task.Delay(1000 * 1).ConfigureAwait(false); await Task.Delay(5000 * 1).ConfigureAwait(false);
} }
}, cancellationToken); }, cancellationToken);
return Task.CompletedTask; return Task.CompletedTask;

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

@ -194,7 +194,7 @@ export default {
v-model="dialogVisible" v-model="dialogVisible"
align-center align-center
destroy-on-close 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> <template #header> <span class="el-dialog__title"> {{editFormTitle}} </span> </template>
<el-row v-loading="editFormloading"> <el-row v-loading="editFormloading">
@ -214,7 +214,7 @@ export default {
/> />
</template> </template>
<template v-else-if="editFormMode==='export'"> <template v-else-if="editFormMode==='export'">
<el-form :model="exportModel" style="height:100%;"> <el-form :model="exportModel">
<el-form-item :label="$t('全部')"> <el-form-item :label="$t('全部')">
<el-switch v-model="exportModel.includeAll" /> <el-switch v-model="exportModel.includeAll" />
</el-form-item> </el-form-item>
@ -224,9 +224,9 @@ export default {
</el-form> </el-form>
</template> </template>
<template v-else-if="editFormMode==='import'"> <template v-else-if="editFormMode==='import'">
<el-form :model="importModel" style="height:100%;"> <el-form :model="importModel" inline>
<el-form-item :label="$t('部分成功')"> <el-form-item :label="$t('部分成功')">
<el-switch v-model="importModel.partal" /> <el-switch v-model="importModel.partial" />
</el-form-item> </el-form-item>
<el-form-item :label="$t('全部替换')"> <el-form-item :label="$t('全部替换')">
<el-switch v-model="importModel.replace" /> <el-switch v-model="importModel.replace" />
@ -235,9 +235,17 @@ export default {
<el-link type="primary" @click="getImportTemplate">{{$t('下载')}}</el-link> <el-link type="primary" @click="getImportTemplate">{{$t('下载')}}</el-link>
</el-form-item> </el-form-item>
<el-form-item :label="$t('文件')"> <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> <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-upload>
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -320,6 +328,7 @@ export default {
children: "children", children: "children",
}); });
const tableRef = ref(null); const tableRef = ref(null);
const uploadRef = ref(null);
const columns = ref([]); const columns = ref([]);
const filterDrawer = ref(false); const filterDrawer = ref(false);
const subDrawer = ref(false); const subDrawer = ref(false);
@ -353,9 +362,8 @@ export default {
const importModel = reactive({ const importModel = reactive({
partial: true, partial: true,
replace: false, replace: false,
template: null,
file: null,
}); });
const fileList = ref([]);
const getSortModel = (model) => { const getSortModel = (model) => {
model.orderBy model.orderBy
.split(",") .split(",")
@ -466,6 +474,7 @@ export default {
//import //import
const url = `${baseUrl}/${item.path}`; const url = `${baseUrl}/${item.path}`;
editFormTitle.value = `${t(item.path)}${schema.value?.title}`; editFormTitle.value = `${t(item.path)}${schema.value?.title}`;
fileList.value = [];
dialogVisible.value = true; dialogVisible.value = true;
} else if (item === "filter") { } else if (item === "filter") {
editFormTitle.value = t("自定义查询"); editFormTitle.value = t("自定义查询");
@ -504,14 +513,20 @@ export default {
delete postData.query["id"]; delete postData.query["id"];
const url = `${baseUrl}/${editFormMode.value}?${qs.stringify(exportModel)}`; const url = `${baseUrl}/${editFormMode.value}?${qs.stringify(exportModel)}`;
const response = await post(url, postData); const response = await post(url, postData);
const downloadUrl = window.URL.createObjectURL(response.data); download(response);
const filename = response.filename;
let link = document.createElement("a");
link.href = downloadUrl;
link.download = filename;
link.click();
window.URL.revokeObjectURL(downloadUrl);
dialogVisible.value = false; 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") { } else if (editFormMode.value === "filter") {
await load(indexUrl); await load(indexUrl);
dialogVisible.value = false; dialogVisible.value = false;
@ -547,9 +562,7 @@ export default {
logic: "and", logic: "and",
}); });
}; };
const getImportTemplate = async () => { const download = (response) => {
const url = `${baseUrl}/${editFormMode.value}`;
const response = await get(url);
const downloadUrl = window.URL.createObjectURL(response.data); const downloadUrl = window.URL.createObjectURL(response.data);
const filename = response.filename; const filename = response.filename;
let link = document.createElement("a"); let link = document.createElement("a");
@ -558,6 +571,14 @@ export default {
link.click(); link.click();
window.URL.revokeObjectURL(downloadUrl); 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 () => { onMounted(async () => {
pushQueryList(); pushQueryList();
const vm = (await get(indexUrl)).data; const vm = (await get(indexUrl)).data;
@ -575,6 +596,7 @@ export default {
return { return {
treeProps, treeProps,
tableRef, tableRef,
uploadRef,
tableLoading, tableLoading,
columns, columns,
showColumn, showColumn,
@ -609,6 +631,8 @@ export default {
showList, showList,
subListQuery, subListQuery,
pushQueryList, 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) => { const post = async (url, data, options, withoutToken = false, withoutCulture = false) => {
url = getUrl(url, withoutCulture); url = getUrl(url, withoutCulture);
const defaultOptions = { let defaultOptions = {
method: "POST", method: "POST",
headers: { headers: {},
"Content-Type": "application/json",
},
}; };
if (!(data instanceof FormData)) {
defaultOptions.headers["Content-Type"] = "application/json";
}
if (options) { if (options) {
Object.assign(defaultOptions, options); Object.assign(defaultOptions, options);
} }
if (data && !defaultOptions.body) { 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); defaultOptions.body = qs.stringify(data);
} else { } else if (defaultOptions.headers["Content-Type"]?.startsWith("application/json")) {
defaultOptions.body = JSON.stringify(data); defaultOptions.body = JSON.stringify(data);
} else {
defaultOptions.body = data;
} }
} }
if (!withoutToken) { if (!withoutToken) {

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

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

Loading…
Cancel
Save