Commit 016c760c authored by 刘坚-丰林-DEV's avatar 刘坚-丰林-DEV

Merge branch 'uploadFile' into 'master'

Upload file

See merge request !1
parents 88fb5d25 0f7bb16e
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
2023-05-07 15:47:29.631 +08:00 [ERR] An error occurred using the connection to database 'BBMChatGLM' on server ''.
2023-05-07 15:47:33.046 +08:00 [ERR] An exception occurred while iterating over the results of a query for context type 'Volo.Abp.BackgroundJobs.EntityFrameworkCore.BackgroundJobsDbContext'.
System.InvalidOperationException: An exception has been raised that is likely due to a transient failure.
---> System.TimeoutException: The operation has timed out.
at Npgsql.Util.NpgsqlTimeout.CheckAndGetTimeLeft()
at Npgsql.Util.NpgsqlTimeout.CheckAndApply(NpgsqlConnector connector)
at Npgsql.Internal.NpgsqlConnector.RawOpen(SslMode sslMode, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken, Boolean isFirstAttempt)
at Npgsql.Internal.NpgsqlConnector.<Open>g__OpenCore|204_1(NpgsqlConnector conn, SslMode sslMode, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken, Boolean isFirstAttempt)
at Npgsql.Internal.NpgsqlConnector.Open(NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
at Npgsql.PoolingDataSource.OpenNewConnector(NpgsqlConnection conn, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
at Npgsql.PoolingDataSource.<Get>g__RentAsync|28_0(NpgsqlConnection conn, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
at Npgsql.NpgsqlConnection.<Open>g__OpenAsync|45_0(Boolean async, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenInternalAsync(Boolean errorsExpected, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenInternalAsync(Boolean errorsExpected, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenAsync(CancellationToken cancellationToken, Boolean errorsExpected)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.SplitQueryingEnumerable`1.AsyncEnumerator.InitializeReaderAsync(AsyncEnumerator enumerator, CancellationToken cancellationToken)
at Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.NpgsqlExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.NpgsqlExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.SplitQueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()
System.InvalidOperationException: An exception has been raised that is likely due to a transient failure.
---> System.TimeoutException: The operation has timed out.
at Npgsql.Util.NpgsqlTimeout.CheckAndGetTimeLeft()
at Npgsql.Util.NpgsqlTimeout.CheckAndApply(NpgsqlConnector connector)
at Npgsql.Internal.NpgsqlConnector.RawOpen(SslMode sslMode, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken, Boolean isFirstAttempt)
at Npgsql.Internal.NpgsqlConnector.<Open>g__OpenCore|204_1(NpgsqlConnector conn, SslMode sslMode, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken, Boolean isFirstAttempt)
at Npgsql.Internal.NpgsqlConnector.Open(NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
at Npgsql.PoolingDataSource.OpenNewConnector(NpgsqlConnection conn, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
at Npgsql.PoolingDataSource.<Get>g__RentAsync|28_0(NpgsqlConnection conn, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
at Npgsql.NpgsqlConnection.<Open>g__OpenAsync|45_0(Boolean async, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenInternalAsync(Boolean errorsExpected, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenInternalAsync(Boolean errorsExpected, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenAsync(CancellationToken cancellationToken, Boolean errorsExpected)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.SplitQueryingEnumerable`1.AsyncEnumerator.InitializeReaderAsync(AsyncEnumerator enumerator, CancellationToken cancellationToken)
at Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.NpgsqlExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.NpgsqlExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.SplitQueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()
2023-05-07 15:47:37.237 +08:00 [ERR] An exception has been raised that is likely due to a transient failure.
System.InvalidOperationException: An exception has been raised that is likely due to a transient failure.
---> System.TimeoutException: The operation has timed out.
at Npgsql.Util.NpgsqlTimeout.CheckAndGetTimeLeft()
at Npgsql.Util.NpgsqlTimeout.CheckAndApply(NpgsqlConnector connector)
at Npgsql.Internal.NpgsqlConnector.RawOpen(SslMode sslMode, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken, Boolean isFirstAttempt)
at Npgsql.Internal.NpgsqlConnector.<Open>g__OpenCore|204_1(NpgsqlConnector conn, SslMode sslMode, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken, Boolean isFirstAttempt)
at Npgsql.Internal.NpgsqlConnector.Open(NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
at Npgsql.PoolingDataSource.OpenNewConnector(NpgsqlConnection conn, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
at Npgsql.PoolingDataSource.<Get>g__RentAsync|28_0(NpgsqlConnection conn, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
at Npgsql.NpgsqlConnection.<Open>g__OpenAsync|45_0(Boolean async, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenInternalAsync(Boolean errorsExpected, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenInternalAsync(Boolean errorsExpected, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenAsync(CancellationToken cancellationToken, Boolean errorsExpected)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.SplitQueryingEnumerable`1.AsyncEnumerator.InitializeReaderAsync(AsyncEnumerator enumerator, CancellationToken cancellationToken)
at Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.NpgsqlExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.NpgsqlExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.SplitQueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
at Volo.Abp.BackgroundJobs.EntityFrameworkCore.EfCoreBackgroundJobRepository.GetWaitingListAsync(Int32 maxResultCount, CancellationToken cancellationToken)
at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
at Volo.Abp.BackgroundJobs.BackgroundJobStore.GetWaitingJobsAsync(Int32 maxResultCount)
at Volo.Abp.BackgroundJobs.BackgroundJobWorker.DoWorkAsync(PeriodicBackgroundWorkerContext workerContext)
at Volo.Abp.BackgroundJobs.BackgroundJobWorker.DoWorkAsync(PeriodicBackgroundWorkerContext workerContext)
at Volo.Abp.BackgroundWorkers.AsyncPeriodicBackgroundWorkerBase.DoWorkAsync(CancellationToken cancellationToken)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BBM.ChatGLM.Dtos
{
public class Results
{
public int? SuccessNum { get; set; } = 0;
public int? FailNum { get; set; } = 0;
}
}
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
......
using BBM.ChatGLM.Dtos;
using BBM.ChatGLM.User;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
using Volo.Abp;
using OfficeOpenXml;
using System.Text.RegularExpressions;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Identity;
namespace BBM.ChatGLM.Controllers
{
[Route("User")]
......@@ -63,5 +62,106 @@ namespace BBM.ChatGLM.Controllers
{
return await _usersAppService.GetTokenAsync();
}
[HttpPost("excelFile")]
public async Task<IActionResult> UploadExcel([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文件为空");
var fileName = file.FileName;
var filePath = Path.Combine("C:\\Excel", 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;
var userDto = await _usersAppService.CreateAsync(userInput);
continue;
}
}
}
catch (Exception ex)
{
failNum++;
}
finally
{
row++;
}
}
xiangying.SuccessNum = (totalRows-1) - failNum;
xiangying.FailNum = failNum;
package.Dispose();
}
return Ok(xiangying);
}
}
}
......@@ -63,7 +63,8 @@
"react-dev-inspector": "^1.7.0",
"react-dom": "^17.0.0",
"react-helmet-async": "^1.2.0",
"umi": "^3.5.0"
"umi": "^3.5.0",
"xlsx": "^0.18.5"
},
"devDependencies": {
"@ant-design/pro-cli": "^2.1.0",
......
......@@ -5,20 +5,28 @@ import {
postDeleteUser,
postResetUser,
postEditUser,
postExcelFile,
postDowload
} from '@/services/chatGLM/api';
import { PlusOutlined } from '@ant-design/icons';
import { PlusOutlined, UploadOutlined } from '@ant-design/icons';
import type { ActionType } from '@ant-design/pro-components';
import { PageContainer } from '@ant-design/pro-components';
import { ProTable } from '@ant-design/pro-components';
import { Button, Col, Divider, Form, Input, Modal, Radio, Row, Switch, message } from 'antd';
import { Button, Col, Divider, Form, Input, Modal, Radio, Row, Switch, message, Upload, Spin } from 'antd';
import classNames from 'classnames';
import { isEmpty } from 'lodash';
import { useRef, useState, useEffect } from 'react';
import React, { useRef, useState, useEffect } from 'react';
import styles from './index.less';
import { Exclamtion } from '@/components/Icons/Icons';
import { LoadingOutlined } from '@ant-design/icons';
const { Item } = Form;
const { Password } = Input;
const antIcon = <LoadingOutlined style={{ fontSize: 24 }} spin />;
const Loading: React.FC = () => <Spin indicator={antIcon} />;
const layout = {
labelCol: { span: 4 },
......@@ -48,6 +56,7 @@ const UserManage = () => {
const [loading, setLoading] = useState(false);
const [ressetLoading, setResetLoading] = useState(false);
const [accountModalName, setAccountModalName] = useState('新建账号');
const [uploadButtonDisable, setUploadButtonDisable] = useState(false);
const [accountForm] = Form.useForm();
const [resetPasswordForm] = Form.useForm();
......@@ -170,6 +179,7 @@ const UserManage = () => {
},
];
const handleOk = () => {
setIsModalAccountOpen(false);
};
......@@ -214,6 +224,7 @@ const UserManage = () => {
const onHandleClickAccountFinish = (values: any) => {
if (accountModalName === '添加账号') {
alert("2");
createdAccount(values);
}
if (accountModalName === '编辑账号') {
......@@ -271,6 +282,19 @@ const UserManage = () => {
});
};
const handleUpload = (file) => {
setUploadButtonDisable(true);
postExcelFile(file).then(res => {
setUploadButtonDisable(false);
message.success(`批量添加用户: 成功人数:${res.successNum} 失败人数:${res.failNum}人`);
})
};
const downloadExcelTemplate = () => {
postDowload();
}
return (
<PageContainer>
<Modal
......@@ -442,6 +466,14 @@ const UserManage = () => {
options={false}
headerTitle="账号列表"
toolBarRender={() => [
<Button onClick={downloadExcelTemplate}>批量添加用户Excel模板</Button>,
<Upload
beforeUpload={handleUpload}
disabled={uploadButtonDisable}
showUploadList={false}
>
{uploadButtonDisable ? <Button><Loading /></Button> : <Button icon={<UploadOutlined />}>Excel表格添加账号</Button>}
</Upload>,
<Button
key="button"
icon={<PlusOutlined />}
......@@ -452,11 +484,11 @@ const UserManage = () => {
type="primary"
>
添加账号
</Button>,
</Button>
]}
/>
</PageContainer>
);
};
export default UserManage;
export default UserManage;
\ No newline at end of file
......@@ -4,19 +4,38 @@ interface ILoginParams {
name: string;
password: string;
}
const request = extend({});
const host = 'https://glm-mangement-api.baibaomen.com';
let host = "";
if (process.env.NODE_ENV === 'development') {
host = 'http://localhost:44315'
} else {
host = 'https://glm-mangement-api.baibaomen.com'
}
request.interceptors.request.use((url, options) => {
const token = JSON.parse(localStorage.getItem('user') || '{}')?.token;
const authHeader = {
Authorization: `Bearer ${token || ''}`,
'Content-Type': 'application/json',
__tenant: '3a0a90fe-9a0d-70f4-200d-a80a41fb6195',
};
let authHeader = null;
if (url == host + "/User/excelFile"){
authHeader= {
Authorization: `Bearer ${token || ''}`,
headers:{'Content-Type': 'multipart/form-data'},
__tenant: '3a0a90fe-9a0d-70f4-200d-a80a41fb6195',
};
}else{
authHeader= {
Authorization: `Bearer ${token || ''}`,
'Content-Type': 'application/json',
__tenant: '3a0a90fe-9a0d-70f4-200d-a80a41fb6195',
};
}
return {
url: url,
options: { ...options, interceptors: true, headers: authHeader },
options: { ...options, interceptors: true ,headers: authHeader},
};
});
......@@ -45,7 +64,7 @@ export interface IPromptWord {
}
export function GetChatGLMToken(): Promise<string> {
return request(host + '/user/token', {
method: 'POST',
method: 'POST'
});
}
......@@ -54,7 +73,6 @@ export function GetPromptList(): Promise<{ items: IPromptWord[] }> {
method: 'POST',
headers: {
Authorization: 'Bearer ' + JSON.parse(localStorage.getItem('user') || '')?.token,
'Content-Type': 'application/json',
},
body: JSON.stringify({ pageIndex: 0, pageSize: 10 }),
});
......@@ -164,6 +182,36 @@ export const postEditUser = (params?: any): Promise<string> => {
});
};
export const postExcelFile = (file) => {
const formData = new FormData();
formData.append('file', file);
return request(host + '/User/excelFile', {
method: 'POST',
body: formData
}).then(response => {
return response;
})
.catch(error => {
throw error;
});
};
export const postDowload = () => {
return request('Template.xlsx', {
method: 'GET',
responseType: 'blob', // 将响应类型设置为二进制流
}).then((response) => {
const url = window.URL.createObjectURL(new Blob([response]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'excelTemplate.xlsx');
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
});
}
export const createSession = (params: any): Promise<any> => {
return request(host + '/ChatSessions/create', {
method: 'POST',
......
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