1 Services.Media.MediaDefaults
namespace Services.Media
{
///
/// 【多媒体默认--类】
///
/// 摘要:
/// 该类中的属性成员实例设定一些常量值,为多媒体服务相关类的定义实现提供相应的支撑。
///
///
public static partial class MediaDefaults
{
#region 用户头像相关配置设定
///
/// 【头像默认目录】
///
/// 摘要:
/// 设定用户头像持久化存储的默认目录。
///
///
public static string DefaultAvatarDirectory => @"\images\Avatar";
///
/// 【默认头像文件名】
///
/// 摘要:
/// 设定用户默认头像图片的文件名。
///
///
public static string DefaultAvatarFileName => "Default.jpg";
///
/// 【默认头像路径】
///
/// 摘要:
/// 设定用户默认头像图片持久化存储的本地格式的相对路径字符串。
///
///
public static string DefaultAvatarPath => @"\images\Avatar\Default.jpg";
#endregion
}
}
2 Web.Areas.Admin.Controllers.CustomerController.Edit
/// name="model">用户模型记录的1个指定实例。
///
/// 【添加用户】
///
/// 摘要:
/// 通过添加用户Razor页面中的数据,把用户实体的1个指定实例持久化到用户表中。
///
///
/// 返回:
/// 用户模型记录的1个指定实例。
///
///
[HttpPost]
public async Task<IActionResult> Edit(CustomerModel model)
{
//后端手动对角色多选下拉框中的输入进行验证。
if (model.SelectedRoleIds.Count <= 0)
{
ModelState.AddModelError("SelectedRoleIds", "必须选择1个角色。");
}
var customer = await _customerService.GetCustomerByIdAsync(model.Id);
var allRoles = await _customerService.GetAllRolesAsync(true);
var newRoles = new List<Role>();
foreach (var role in allRoles)
if (model.SelectedRoleIds.Contains(role.Id))
newRoles.Add(role);
if (ModelState.IsValid)
{
customer.Username = model.Username;
customer.Email = model.Email;
customer.Phone= model.Phone;
customer.IsSystemAccount = model.IsSystemAccount;
customer.Active = model.Active;
customer.Deleted = model.Deleted;
if(!string.IsNullOrEmpty(model.Password))
{
var saltKey = _encryptionService.CreateSaltKey(CustomerServicesDefaults.PasswordSaltKeySize);
customer.PasswordSalt = saltKey;
customer.Password = _encryptionService.CreatePasswordHash(model.Password, saltKey, CustomerServicesDefaults.DefaultHashedPasswordFormat);
}
if(model.FormFile != null)
{
if (!string.IsNullOrEmpty(customer.Avatar)&&!_nopFileProvider.GetFileName(customer.Avatar).Equals(MediaDefaults.DefaultAvatarFileName))
{
var oldAvatarAbsolutePath = _nopFileProvider.GetAbsolutePath(MediaDefaults.DefaultAvatarDirectory, _nopFileProvider.GetFileName(customer.Avatar));
_nopFileProvider.DeleteFile(oldAvatarAbsolutePath);
}
var filename = Guid.NewGuid().ToString() + _nopFileProvider.GetFileExtension(model.FormFile.FileName);
var newAvatarAbsolutePath = _nopFileProvider.GetAbsolutePath(MediaDefaults.DefaultAvatarDirectory, filename);
using FileStream fileStream = new FileStream(newAvatarAbsolutePath, FileMode.Create);
await model.FormFile.CopyToAsync(fileStream);
customer.Avatar = "/images/Avatar/" + filename;
}
var currentRoleIds = (await _customerService.GetRolesAsync(customer,true)).Select(role => role.Id).ToArray();
foreach (var role in allRoles)
{
if (model.SelectedRoleIds.Contains(role.Id))
{
if(role.Name== CustomerDefaults.AdministratorsRoleName)
customer.IsSystemAccount = true;
//把用户所属角色持久化到用户角色映射表中。
if (currentRoleIds.All(roleId => roleId != role.Id))
await _customerService.AddCustomerRoleMappingAsync(new CustomerRoleMapping { CustomerId = customer.Id, RoleId = role.Id });
}
else
{
if (role.Name == CustomerDefaults.AdministratorsRoleName)
customer.IsSystemAccount = false;
//把用户不属角色从用户角色映射表中删除。
if (currentRoleIds.Any(roleId => roleId == role.Id))
await _customerService.RemoveCustomerRoleMappingAsync(customer, role);
}
}
await _customerService.UpdateCustomerAsync(customer);
ViewBag.RefreshPage = true;
}
model = await _customerModelFactory.PrepareCustomerModelAsync(model, customer, true);
return View(model);
}
3 Web\Areas\Admin\Views\Customer\Edit.cshtml
@model Web.Areas.Admin.Models.Customers.CustomerModel
@{
ViewData["Title"] = "Edit";
Layout = "~/Areas/Admin/Views/Shared/_LayoutPopup.cshtml";
}
@section styles
{
rel="stylesheet" href="~/lib/bootstrap-fileinput-5.5.2/css/fileinput.css" />
href="~/lib/bootstrap-fileinput-5.5.2/themes/explorer-fa5/theme.css" media="all" rel="stylesheet" type="text/css" />
.kv-avatar .krajee-default.file-preview-frame,.kv-avatar .krajee-default.file-preview-frame:hover {
margin: 0;
padding: 0;
border: none;
box-shadow: none;
text-align: center;
}
.kv-avatar {
display: inline-block;
}
.kv-avatar .file-input {
display: table-cell;
width: 213px;
}
.kv-reqd {
color: red;
font-family: monospace;
font-weight: normal;
}
}
@if (ViewBag.RefreshPage == true)
{
}
asp-route-btnId="@Context.Request.Query["btnId"]" enctype="multipart/form-data" method="post"> asp-for="Id" class="form-control" /> @if (Model.Username == CustomerDefaults.DefaultSystemCustomer) { asp-for="Username" class="form-control" readonly /> } else { asp-for="Username" class="form-control" /> } asp-validation-for="Username" class="text-danger"> asp-for="Email" class="form-control" /> asp-validation-for="Email" class="text-danger"> asp-for="Phone" class="form-control" /> asp-validation-for="Phone" class="text-danger"> asp-for="Password" class="form-control" /> asp-validation-for="Password" class="text-danger"> @if (Model.Username == CustomerDefaults.DefaultSystemCustomer) { class="form-check-input checkBox25" asp-for="Active" onclick="return false;" checked /> } else { class="form-check-input checkBox25" asp-for="Active" /> } @Html.DisplayNameFor(model => model.Active) @if (Model.Username == CustomerDefaults.DefaultSystemCustomer) { class="form-check-input checkBox25" asp-for="Deleted" onclick="return false;" /> } else { class="form-check-input checkBox25" asp-for="Deleted" /> } @Html.DisplayNameFor(model => model.Deleted) @if (Model.Username == CustomerDefaults.DefaultSystemCustomer) { } else { } asp-validation-for="SelectedRoleIds" class="text-danger"> asp-for="FormFile" type="file" class="file" /> type="submit" value="保存" class="btn btn-primary" />
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
var imageArray = @Html.Raw(Json.Serialize(Model.Avatar));
$(document).ready(function () {
$("#SelectedRoleIds").kendoMultiSelect({
select: function (e) {
var current = this.value();
if (this.dataSource.view()[e.item.index()].value === "0") {
this.value("");
}
else if (current.indexOf("0") !== -1) {
current = $.grep(current, function (value) {
return value !== "0";
});
this.value(current);
}
},
change: function (e) {
if (this.value().length === 0)
this.value(["0"]);
}
}).data("kendoMultiSelect");
});
//把“bootstrap-fileinput”设定上传控件,注意:如果使用“bootstrap-fileinput”进行验证,所选择的上传文件与验证规则不符“FormFile”为: null;也可以定义的后端手动验证来验证选择的上传文件。
$("#FormFile").fileinput({
theme: 'fa5',
language: 'zh', //设置本地化语言(简体中文)。
//bootstrap-fileinput插件UI相关的初始化设定。
showClose: false,//是否显示关闭按钮。
showCaption: true,//是否显示标题(上传输入框控件,默认值:true)。
showRemove: false,//是否显示删除按钮。
showUpload: false,//是否显示上传按钮。
dropZoneEnabled: false,//不支持拖拽(是否显示拖拽区域,默认值:true)。
dropZoneTitle: "可以将图片拖放到这里",//拖拽区域显示文字(默认值:true)。
layoutTemplates: {
//actionDelete:'', //去除上传预览的缩略图中的删除图标。
actionUpload: '',//去除上传预览缩略图中的上传图片。
actionZoom: '', //去除上传预览缩略图详情的图标(默认值:有图标)。
actionDownload: '', //去除上传预览缩略图中的下载图标。
actionRotate: '', //去除上传预览缩略图中的旋转图标。
},
//编辑时初始加载预览图片配置。
overwriteInitial: true,//覆盖初始预览内容和标题。
initialPreviewAsData: true,//是否将初始预览内容集解析为数据而不是原始标记语言。
initialPreview: imageArray,//预览图片地址,多文件是数组形式。
//上传相关设定。
//required: true,//必须选择1个上传文件。
maxFileCount: 1, //每次上传允许的最大文件数。如果设置为0,则表示允许的文件数是无限制的。默认为0
allowedFileExtensions: ['jpeg', 'jpg', 'jpe', "gif", "png", "bmp"],//允许上传文件的类型。
uploadUrl: "#", //文件上传的行为方法,注意:如果要想在上传预览的缩略图中显示:删除、上传、缩略、下载、旋转等图标,必须的定义该属性。
// uploadAsync:多文件上传时如果使用bootstrap-fileinput插件内置控件或方法,该参数实例为:false时,则会把列表中的所有文件的数据同时提交到后台行为方法的对应参数中;
// 如果该参数实例为:true,列表中的每1个文件都向提交到后台行为方法的对应参数中提交1次数据(即有多少文件向后台方法提交多少次,默认值:true)。
uploadAsync: false,
maxFileSize: 10240, //单个上传文件最大值(10MB,.NetCore的所有上传文件的最大默认值是:30MB=30720KB),单位为kb,如果为0表示不限制文件大小。
}).on('filebatchselected', function (event, files) {//批量选择操作后回调函数。
var _maxRequestSize = 30720;
_allFileSize = 0;
$.each(files, function (idx, item) {
_allFileSize += (item.size / 1024);
});
_allFileSize = parseFloat(_allFileSize.toFixed(2));
if (_allFileSize > _maxRequestSize) {
var msg = "选择的文件总大小(" + (_allFileSize / 1024).toFixed(2) + "MB)超出限制(" + (_maxRequestSize / 1024).toFixed(2) + "MB)";
//如果所选择的上传文件的总大小大于限定值,则弹出警告窗口,如果点击弹出警告窗口中的“确定”按钮,则删除已经选择的所有的上传文件。
$('#FormFileList').fileinput('clear');
alert(msg);
};
//$(this).fileinput("upload");//选择上传文件完成后,自动对文件进行上传操作。
})
//把“Bootstrap v5”设定为jquery.validate.unobtrusive.js中验证样式。
$.validator.setDefaults({
errorClass: "",
validClass: "",
highlight: function (element, errorClass, validClass) {
$(element).addClass("is-invalid").removeClass("is-valid");
$(element.form).find("[data-valmsg-for=" + element.id + "]").addClass("invalid-feedback");
},
unhighlight: function (element, errorClass, validClass) {
$(element).addClass("is-valid").removeClass("is-invalid");
$(element.form).find("[data-valmsg-for=" + element.id + "]").removeClass("invalid-feedback");
},
});
}
对以上功能更为具体实现和注释见:230612_025ShopRazor(用户编辑与bootstrap-fileinput头像上传)。