Commit c8affe6c authored by 文旺-丰林-DEV's avatar 文旺-丰林-DEV

Merge branch 'uploadFile' into 'master'

Upload file

See merge request !4
parents 6284bf37 13f7e567
......@@ -328,3 +328,4 @@ build
node_modules
*.txt
This source diff could not be displayed because it is too large. You can view the blob instead.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BBM.ChatGLM.Dtos
{
public class ImportUsersResult
{
public List<Dtos.Results> Results { get; set; }
public int FailNum { get; set; }
public int SuccessNum { get; set; }
}
}
......@@ -8,7 +8,13 @@ namespace BBM.ChatGLM.Dtos
{
public class Results
{
public int? SuccessNum { get; set; } = 0;
public string userName { get; set; }
public string phone { get; set; }
public string role { get; set; }
public string state { get; set; }
public string failureReason { get; set; }
public int? SuccessNum { get; set; } = 0;
public int? FailNum { get; set; } = 0;
}
}
using BBM.ChatGLM.Dtos;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
......@@ -17,5 +19,7 @@ namespace BBM.ChatGLM.User
Task<PagedResultDto<UserDto>> PageAsync(UserPageInput input);
Task<List<string>> GetRolesAsync();
Task<string> GetTokenAsync();
Task<ImportUsersResult> CreateUsersByExcel([FromForm] IFormFile file);
}
}
using BBM.ChatGLM.Dtos;
using Lion.AbpPro.BasicManagement.Roles;
using Lion.AbpPro.BasicManagement.Users;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using NetTopologySuite.Mathematics;
using OfficeOpenXml;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Logical;
using System.ComponentModel.DataAnnotations;
using System.Text.Json;
using System.Text.RegularExpressions;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Identity;
......@@ -120,5 +125,161 @@ namespace BBM.ChatGLM.User
throw new BusinessException("BBM.ChatGLM:100012");
}
}
[Authorize(ChatGLMPermissions.UsersManagement.Create)]
public async Task<ImportUsersResult> CreateUsersByExcel([FromForm] IFormFile file)
{
/**
* [FromForm]
* 操作步骤
* 1、React中,使用antd的Upload组件来上传Excel表格数据,并且在上传之前需要将表格数据转换成FormData。
* 2、在ASP.NET中,建立一个Controller用于接收上传的文件,并且使用[HttpPost]属性来指定使用POST方法接收请求。
* 3、在Controller中,使用IFormFile接口来接收上传的Excel文件,然后使用EPPlus等工具来读取Excel文件数据
* 4、将读取到的Excel数据进行处理,例如存储到数据库中或者进行数据分析等操作
*/
List<Dtos.Results> results = new List<Dtos.Results>();
Dtos.Results xiangying = new Dtos.Results();
var failNum = 0;
if (file == null)
{
xiangying = FailReason("", "", "", "", "Excel文件为空");
results.Add(xiangying);
return new ImportUsersResult
{
Results = new List<Dtos.Results> { },
FailNum = 0,
SuccessNum = 0
};
}
string directoryPath = Environment.CurrentDirectory + @"\Excels";
if (!Directory.Exists(directoryPath))
Directory.CreateDirectory(directoryPath);
var filePath = Path.Combine(directoryPath, file.FileName);
using (var stream = new FileStream(filePath, FileMode.Create))
{
await file.CopyToAsync(stream);
}
using (var package = new ExcelPackage(new FileInfo(filePath)))
{
var worksheet = package.Workbook.Worksheets["sheet1"];
var totalRows = worksheet.Dimension.Rows;
var row = 2;
var userName = "";
var phoneNumber = "";
var userRole = "";
while (row <= totalRows)
{
try
{
userName = worksheet.Cells[row, 1].Value?.ToString().Replace(" ", "") ?? "";
phoneNumber = worksheet.Cells[row, 2].Value?.ToString().Replace(" ", "") ?? "";
userRole = worksheet.Cells[row, 3].Value?.ToString().Replace(" ", "") ?? "";
userName = Regex.Replace(userName, @"\s", "");
phoneNumber = Regex.Replace(phoneNumber, @"\s", "");
userRole = Regex.Replace(userRole, @"\s", "");
if (string.IsNullOrEmpty(userName))
{
failNum++;
xiangying = FailReason(userName, phoneNumber, userRole, "失败", "用户名不正确");
}
else if (userName.Length > 20)
{
failNum++;
xiangying = FailReason(userName, phoneNumber, userRole, "失败", "用户名超出长度限制");
}
else if (!Regex.IsMatch(userName, @"^[\u4e00-\u9fa5a-zA-Z]+$"))
{
failNum++;
xiangying = FailReason(userName, phoneNumber, userRole, "失败", "用户名包含特殊符号");
}
else if (string.IsNullOrEmpty(phoneNumber))
{
failNum++;
xiangying = FailReason(userName, phoneNumber, userRole, "失败", "手机号码不正确");
}
else if (!Regex.IsMatch(phoneNumber, @"^(133|153|189|180|181|177|173|199|174|141
|139|138|137|136|135|134|159|158|157|150|151|152|147|188|187|182|183|184|178|198
|130|131|132|146|156|155|166|186|185|145|175|176
|170|171
|123)\d{8}$"))
{
failNum++;
xiangying = FailReason(userName, phoneNumber, userRole, "失败", "手机号码格式不正确");
}
else if (phoneNumber.Length > 11)
{
failNum++;
xiangying = FailReason(userName, phoneNumber, userRole, "失败", "手机号码超出长度限制");
}
else if (userRole != "普通用户" && userRole != "管理员")
{
failNum++;
xiangying = FailReason(userName, phoneNumber, userRole, "失败", "角色输入不正确");
}
else
{
var password = "Zs." + phoneNumber.Substring(phoneNumber.Length - 6);
if (userRole == "管理员")
{
userRole = "admin";
}
UserCreateInput userInput = new UserCreateInput();
userInput.Name = userName;
userInput.UserName = userName;
userInput.Password = password;
userInput.Role = userRole;
userInput.IsActive = true;
var res = await CreateAsync(userInput);
xiangying = FailReason(userName, phoneNumber, userRole, "成功", "");
}
}
catch (Exception ex)
{
failNum++;
xiangying = FailReason(userName, phoneNumber, userRole, "失败", "已存在当前用户,重复添加失败");
}
finally
{
row++;
results.Add(xiangying);
}
}
return new ImportUsersResult
{
Results = results,
FailNum = failNum,
SuccessNum = (totalRows - 1) - failNum
};
}
}
public Dtos.Results FailReason(string userName, string phone, string role, string state, string reason)
{
Dtos.Results results = new Dtos.Results();
results.userName = userName;
results.phone = phone;
results.role = role;
results.state = state;
results.failureReason = reason;
return results;
}
}
}
......@@ -66,105 +66,9 @@ namespace BBM.ChatGLM.Controllers
}
[HttpPost("excelFile")]
public async Task<IActionResult> UploadExcel([FromForm] IFormFile file)
public async Task<ImportUsersResult> CreateUsersByExcel([FromForm] IFormFile file)
{
/**
* [FromForm]
* 操作步骤
* 1、React中,使用antd的Upload组件来上传Excel表格数据,并且在上传之前需要将表格数据转换成FormData。
* 2、在ASP.NET中,建立一个Controller用于接收上传的文件,并且使用[HttpPost]属性来指定使用POST方法接收请求。
* 3、在Controller中,使用IFormFile接口来接收上传的Excel文件,然后使用EPPlus等工具来读取Excel文件数据
* 4、将读取到的Excel数据进行处理,例如存储到数据库中或者进行数据分析等操作
*/
Dtos.Results xiangying = new Dtos.Results();
var failNum = 0;
if (file == null)
return BadRequest("Excel文件为空");
string directoryPath = Environment.CurrentDirectory + @"\Excels";
if (!Directory.Exists(directoryPath))
Directory.CreateDirectory(directoryPath);
var filePath = Path.Combine(directoryPath, file.FileName);
using (var stream = new FileStream(filePath, FileMode.Create))
{
await file.CopyToAsync(stream);
}
using (var package = new ExcelPackage(new FileInfo(filePath)))
{
var worksheet = package.Workbook.Worksheets["sheet1"];
var totalRows = worksheet.Dimension.Rows;
var row = 2;
var userName = "";
var phoneNumber = "";
var userRole = "";
while (row <= totalRows)
{
try
{
userName = worksheet.Cells[row, 1].Value?.ToString() ?? "";
phoneNumber = worksheet.Cells[row, 2].Value?.ToString() ?? "";
userRole = worksheet.Cells[row, 3].Value?.ToString() ?? "";
if (userName == "" || phoneNumber == "" || userName.Length>50 || userRole == "" || (userRole != "普通用户" && userRole != "管理员"))
{
failNum++;
}
else
{
if (!Regex.IsMatch(phoneNumber, @"^(133|153|189|180|181|177|173|199|174|141
|139|138|137|136|135|134|159|158|157|150|151|152|147|188|187|182|183|184|178|198
|130|131|132|146|156|155|166|186|185|145|175|176
|170|171
|123)\d{8}$"))
{
failNum++;
}
else
{
var password = "Zs" + phoneNumber.Substring(phoneNumber.Length - 6);
if (userRole == "管理员")
{
userRole = "admin";
}
UserCreateInput userInput = new UserCreateInput();
userInput.Name = userName;
userInput.UserName = userName;
userInput.Password = password;
userInput.Role = userRole;
userInput.IsActive = true;
await _usersAppService.CreateAsync(userInput);
continue;
}
}
}
catch (Exception ex)
{
failNum++;
}
finally
{
row++;
}
}
xiangying.SuccessNum = (totalRows-1) - failNum;
xiangying.FailNum = failNum;
package.Dispose();
}
return Ok(xiangying);
return await _usersAppService.CreateUsersByExcel(file);
}
}
......
......@@ -34,6 +34,20 @@ import styles from './index.less';
import { Exclamtion } from '@/components/Icons/Icons';
import { LoadingOutlined } from '@ant-design/icons';
import UserModal from './userModal';
interface IUserResult {
userName: string;
role: string;
state: string;
phone: string;
failureReason: string
}
export interface ICreateUserResult {
results: IUserResult[],
failNum: number,
successNum: number,
}
const { Item } = Form;
const { Password } = Input;
......@@ -71,6 +85,8 @@ const UserManage = () => {
const [uploadButtonDisable, setUploadButtonDisable] = useState(false);
const [accountForm] = Form.useForm();
const [resetPasswordForm] = Form.useForm();
const [isModalOpen, setIsModalOpen] = useState(false);
const [users, setUsers] = useState<ICreateUserResult>();
useEffect(() => {
getRole().then((res) => {
......@@ -295,16 +311,18 @@ const UserManage = () => {
const handleUpload = (file) => {
setUploadButtonDisable(true);
postExcelFile(file).then((res) => {
postExcelFile(file).then(data => {
setUploadButtonDisable(false);
actionRef.current?.reload();
message.success(`批量添加用户: 成功人数:${res.successNum} 失败人数:${res.failNum}人`);
setUsers(data);
setTimeout(() => {
setIsModalOpen(true);
}, 100)
});
};
const downloadExcelTemplate = () => {
postDowload();
};
}
return (
<PageContainer>
......@@ -478,18 +496,13 @@ const UserManage = () => {
headerTitle="账号列表"
toolBarRender={() => [
<Button>
<a href="https://baibaomen.oss-cn-hangzhou.aliyuncs.com/zhensheng/excelTemplate.xlsx">
批量添加用户模板下载
</a>
</Button>,
<Upload beforeUpload={handleUpload} disabled={uploadButtonDisable} showUploadList={false}>
{uploadButtonDisable ? (
<Button>
<Loading />
</Button>
) : (
<Button icon={<UploadOutlined />}>批量添加账号</Button>
)}
<a href='https://baibaomen.oss-cn-hangzhou.aliyuncs.com/zhensheng/excelTemplate.xlsx'>批量添加用户Excel模板</a></Button>,
<Upload
beforeUpload={handleUpload}
disabled={uploadButtonDisable}
showUploadList={false}
>
{uploadButtonDisable ? <Button color='white'><Loading /></Button> : <Button icon={<UploadOutlined /> }>Excel表格添加账号</Button>}
</Upload>,
<Button
key="button"
......@@ -504,6 +517,7 @@ const UserManage = () => {
</Button>,
]}
/>
<UserModal isModalOpen={isModalOpen} data={users} onClose={()=>{ setIsModalOpen(false) }}></UserModal>
</PageContainer>
);
};
......
import { Modal, Row, Table, Tag, Col } from 'antd';
import { ICreateUserResult } from '.';
const UserModal = (props: {data?: ICreateUserResult, isModalOpen:boolean, onClose: () => void }) => {
const { data, isModalOpen, onClose } = props;
const columns = [
{
title: '用户名',
dataIndex: 'userName',
key: 'userName',
},
{
title: '手机号码',
dataIndex: 'phone',
key: 'phone',
},
{
title: '用户角色',
dataIndex: 'role',
key: 'role',
},
{
title: '状态',
dataIndex: 'state',
key: 'state',
render: (_, record: any) => {
let color = record?.state === '失败' ? 'volcano' : 'green';
return <Tag color={color}> {record?.state} </Tag>;
}
},
{
title: '原因',
dataIndex: 'failureReason',
key: 'failureReason',
},
];
return (
<>
{
data && <Row>
<Modal title="导入结果" width={'50vw'} open={isModalOpen} onCancel={onClose} onOk={onClose}>
<Row>
<Col span={24}>
共导入用户&nbsp;<Tag style={{ margin:'0 4px' }}>{data.successNum + data.failNum}</Tag>个。 成功<Tag style={{ margin:'0 4px' }} color='green'>{data.successNum}</Tag>&nbsp;,失败<Tag style={{ margin:'0 4px' }} color='volcano'>{data.failNum}</Tag>个。
</Col>
</Row>
<br></br>
<Table columns={columns} dataSource={data.results} pagination={false} />
</Modal>
</Row>
}
</>
);
};
export default UserModal;
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment