Skip to content

Commit

Permalink
feat(mis-web): 文件导出功能增加编码选项 (#1322)
Browse files Browse the repository at this point in the history
### 问题
当前导出的内容都是UTF8,用户在用excel看得时候很麻烦

![image](https://github.com/PKUHPC/SCOW/assets/78541912/1be0b5e1-5972-4fcf-816c-23799c4022d9)
### 解决
用户,账户,租户,平台的操作日志导出
租户管理,平台管理用户列表导出
租户管理中的账户管理中的账户列表和平台管理的账户列表导出
账户管理的消费记录,租户管理中的账户消费记录,平台管理中财务管理的消费记录导出
账户管理的充值记录,租户管理中的账户充值记录,租户充值记录,平台管理的租户充值记录导出
全部增加编码选项,可选GB18030和UTF-8两种编码

![image](https://github.com/PKUHPC/SCOW/assets/78541912/9b26d624-3ec2-47ee-9ca3-0ef894ff2ee2)
  • Loading branch information
cuvalign authored Jun 25, 2024
1 parent a7c733b commit 4ab2cec
Show file tree
Hide file tree
Showing 20 changed files with 270 additions and 131 deletions.
5 changes: 5 additions & 0 deletions .changeset/light-pillows-live.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@scow/mis-web": patch
---

导出数据时增加编码选项
15 changes: 8 additions & 7 deletions apps/mis-web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"license": "Mulan PSL v2",
"repository": "https://github.com/PKUHPC/SCOW",
"dependencies": {
"@ant-design/cssinjs": "1.19.1",
"@ant-design/icons": "5.3.6",
"@ddadaal/next-typed-api-routes-runtime": "0.8.2",
"@ddadaal/tsgrpc-client": "0.17.7",
Expand All @@ -32,15 +33,18 @@
"@scow/lib-auth": "workspace:*",
"@scow/lib-config": "workspace:*",
"@scow/lib-decimal": "workspace:*",
"@scow/lib-operation-log": "workspace:*",
"@scow/lib-web": "workspace:*",
"@scow/protos": "workspace:*",
"@scow/utils": "workspace:*",
"@scow/lib-operation-log": "workspace:*",
"@scow/rich-error-model": "workspace:*",
"@scow/utils": "workspace:*",
"@sinclair/typebox": "0.32.20",
"antd": "5.16.0",
"csv-stringify": "6.4.6",
"dayjs": "1.11.10",
"google-protobuf": "3.21.2",
"http-proxy": "1.18.1",
"iconv-lite": "^0.6.3",
"less": "4.2.0",
"mime-types": "2.1.35",
"next": "14.1.4",
Expand All @@ -51,15 +55,12 @@
"react-async": "10.0.1",
"react-dom": "18.2.0",
"react-is": "18.2.0",
"react-typed-i18n": "2.3.0",
"recharts": "^2.7.3",
"simstate": "3.0.1",
"styled-components": "6.1.8",
"tslib": "2.6.2",
"typescript": "5.4.3",
"http-proxy": "1.18.1",
"@ant-design/cssinjs": "1.19.1",
"react-typed-i18n": "2.3.0",
"csv-stringify": "6.4.6"
"typescript": "5.4.3"
},
"devDependencies": {
"@ddadaal/next-typed-api-routes-cli": "0.9.1",
Expand Down
51 changes: 28 additions & 23 deletions apps/mis-web/src/components/OperationLogTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ import { useAsync } from "react-async";
import { api } from "src/apis";
import { FilterFormContainer } from "src/components/FilterFormContainer";
import { getI18nCurrentText, prefix, useI18n, useI18nTranslate, useI18nTranslateToString } from "src/i18n";
import { Encoding } from "src/models/exportFile";
import {
getOperationDetail,
getOperationResultTexts,
getOperationTypeTexts, OperationCodeMap, OperationLog,
OperationLogQueryType,
OperationResult, OperationSortBy, OperationSortOrder } from "src/models/operationLog";
OperationResult, OperationSortBy, OperationSortOrder,
} from "src/models/operationLog";
import { ExportFileModaLButton } from "src/pageComponents/common/exportFileModal";
import { MAX_EXPORT_COUNT, urlToExport } from "src/pageComponents/file/apis";
import { User } from "src/stores/UserStore";
Expand Down Expand Up @@ -77,7 +79,7 @@ export const OperationLogTable: React.FC<Props> = ({ user, queryType, accountNam

const { message } = App.useApp();

const [ query, setQuery ] = useState<FilterForm>(() => {
const [query, setQuery] = useState<FilterForm>(() => {
return {
operatorUserId: undefined,
operationType: undefined,
Expand All @@ -104,22 +106,24 @@ export const OperationLogTable: React.FC<Props> = ({ user, queryType, accountNam
};

const promiseFn = useCallback(async () => {
return await api.getOperationLogs({ query: {
type: queryType,
operatorUserIds: getOperatorUserIds().join(","),
operationType: query.operationType as OperationType,
operationResult: query.operationResult,
startTime: query.operationTime?.[0].toISOString(),
endTime: query.operationTime?.[1].toISOString(),
operationTargetAccountName: accountName,
operationDetail: query.operationDetail,
customEventType: query.customEventType,
page: pageInfo.page,
pageSize: pageInfo.pageSize,
// 新增排序参数
sortBy: sorter.field,
sortOrder: sorter.order,
} });
return await api.getOperationLogs({
query: {
type: queryType,
operatorUserIds: getOperatorUserIds().join(","),
operationType: query.operationType as OperationType,
operationResult: query.operationResult,
startTime: query.operationTime?.[0].toISOString(),
endTime: query.operationTime?.[1].toISOString(),
operationTargetAccountName: accountName,
operationDetail: query.operationDetail,
customEventType: query.customEventType,
page: pageInfo.page,
pageSize: pageInfo.pageSize,
// 新增排序参数
sortBy: sorter.field,
sortOrder: sorter.order,
},
});
}, [query, pageInfo, queryType, accountName, tenantName, sorter]);

const { data, isLoading } = useAsync({ promiseFn });
Expand All @@ -128,7 +132,7 @@ export const OperationLogTable: React.FC<Props> = ({ user, queryType, accountNam
return await api.getCustomEventTypes({});
}, []);

const { data: customEventTypes, isLoading : customEventTypesLoading } = useAsync({
const { data: customEventTypes, isLoading: customEventTypesLoading } = useAsync({
promiseFn: getCustomEventTypesPromise,
});

Expand Down Expand Up @@ -171,19 +175,20 @@ export const OperationLogTable: React.FC<Props> = ({ user, queryType, accountNam
const handleTableChange = (pagination, _, sorter) => {
setPageInfo({ page: pagination.current, pageSize: pagination.pageSize });
setSorter({
field:sorter.field === "operationLogId" ? "id" : sorter.field,
field: sorter.field === "operationLogId" ? "id" : sorter.field,
order: sorter.order,
});
};

const handleExport = async (columns: string[]) => {
const handleExport = async (columns: string[], encoding: Encoding) => {
const total = data?.totalCount ?? 0;
if (total > MAX_EXPORT_COUNT) {
message.error(t(pCommon("exportMaxDataErrorMsg"), [MAX_EXPORT_COUNT]));
} else if (total <= 0) {
message.error(t(pCommon("exportNoDataErrorMsg")));
} else {
window.location.href = urlToExport({
encoding,
exportApi: "exportOperationLog",
columns,
count: total,
Expand All @@ -207,7 +212,7 @@ export const OperationLogTable: React.FC<Props> = ({ user, queryType, accountNam

const exportOptions = useMemo(() => {
return [
{ label: t(p("operationCode")), value: "operationCode" },
{ label: t(p("operationCode")), value: "operationCode" },
{ label: t(p("operationType")), value: "operationType" },
{ label: t(p("operationDetail")), value: "operationDetail" },
{ label: t(p("operationResult")), value: "operationResult" },
Expand Down Expand Up @@ -336,7 +341,7 @@ export const OperationLogTable: React.FC<Props> = ({ user, queryType, accountNam
<Table.Column<OperationLog>
dataIndex="operationResult"
title={t(p("operationResult"))}
render={(operationResult) => OperationResultTexts[operationResult] }
render={(operationResult) => OperationResultTexts[operationResult]}
sorter={true}
/>
<Table.Column<OperationLog>
Expand Down
1 change: 1 addition & 0 deletions apps/mis-web/src/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ export default {
title: "Export Data",
subTitle: "Select the fields to export",
errorMsg: "Please select one field at least!",
encoding: "Encoding",
},
paymentTable: {
total: "Total",
Expand Down
1 change: 1 addition & 0 deletions apps/mis-web/src/i18n/zh_cn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@ export default {
title: "导出数据",
subTitle: "请选择需要导出的字段",
errorMsg: "请至少选择一项进行导出",
encoding: "编码",
},
paymentTable:{
total:"总数",
Expand Down
16 changes: 16 additions & 0 deletions apps/mis-web/src/models/exportFile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* Copyright (c) 2022 Peking University and Peking University Institute for Computing and Digital Economy
* SCOW is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/

export enum Encoding {
GB18030 = "gb18030",
UTF8 = "utf-8",
}
30 changes: 17 additions & 13 deletions apps/mis-web/src/pageComponents/accounts/AccountTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import React, { useMemo, useState } from "react";
import { api } from "src/apis";
import { FilterFormContainer, FilterFormTabs } from "src/components/FilterFormContainer";
import { prefix, useI18nTranslateToString } from "src/i18n";
import { Encoding } from "src/models/exportFile";
import { AccountState, DisplayedAccountState, getDisplayedStateI18nTexts } from "src/models/User";
import { ExportFileModaLButton } from "src/pageComponents/common/exportFileModal";
import { MAX_EXPORT_COUNT, urlToExport } from "src/pageComponents/file/apis";
Expand Down Expand Up @@ -97,7 +98,7 @@ export const AccountTable: React.FC<Props> = ({

const dataMatchedState =
rangeSearchStatus === FilteredTypes.ALL ||
(rangeSearchStatus !== FilteredTypes.ALL &&
(rangeSearchStatus !== FilteredTypes.ALL &&
x.displayedState === FilteredTypes[rangeSearchStatus]);

return dataMatchedAccount && dataMatchedOwner && dataMatchedState;
Expand All @@ -109,18 +110,19 @@ export const AccountTable: React.FC<Props> = ({

const searchData = useMemo(() => data ? data.results.filter((x) => (
(!query.accountName || x.accountName.includes(query.accountName))
&& (!query.ownerIdOrName || x.ownerId.includes(query.ownerIdOrName) || x.ownerName.includes(query.ownerIdOrName))
&& (!query.ownerIdOrName || x.ownerId.includes(query.ownerIdOrName) || x.ownerName.includes(query.ownerIdOrName))
)) : undefined, [data, query]);

const accountStatusCount = useMemo(() => {
if (!searchData) return {
DISPLAYED_BLOCKED : 0,
DISPLAYED_FROZEN : 0,
DISPLAYED_BLOCKED: 0,
DISPLAYED_FROZEN: 0,
DISPLAYED_BELOW_BLOCK_THRESHOLD: 0,
DISPLAYED_NORMAL: 0,
ALL : 0 };
ALL: 0,
};
const counts = {
DISPLAYED_FROZEN: searchData.filter((account) =>
DISPLAYED_FROZEN: searchData.filter((account) =>
account.displayedState === DisplayedAccountState.DISPLAYED_FROZEN).length,
DISPLAYED_BLOCKED: searchData.filter((account) =>
account.displayedState === DisplayedAccountState.DISPLAYED_BLOCKED).length,
Expand All @@ -143,7 +145,7 @@ export const AccountTable: React.FC<Props> = ({
setCurrentSortInfo({ field: null, order: null });
};

const handleExport = async (columns: string[]) => {
const handleExport = async (columns: string[], encoding: Encoding) => {

const total = filteredData?.length || 0;

Expand All @@ -157,6 +159,7 @@ export const AccountTable: React.FC<Props> = ({
exportApi: "exportAccount",
columns,
count: total,
encoding,
query: {
accountName: query.accountName,
blocked: rangeSearchStatus === "DISPLAYED_BLOCKED",
Expand All @@ -181,8 +184,8 @@ export const AccountTable: React.FC<Props> = ({
] : [];
const remaining = [
{ label: t(pCommon("balance")), value: "balance" },
{ label: t(p("blockThresholdAmount")), value: "blockThresholdAmount" },
{ label: t(p("status")), value: "displayedState" },
{ label: t(p("blockThresholdAmount")), value: "blockThresholdAmount" },
{ label: t(p("status")), value: "displayedState" },
{ label: t(p("comment")), value: "comment" },
];
return [...common, ...tenant, ...remaining];
Expand Down Expand Up @@ -281,13 +284,13 @@ export const AccountTable: React.FC<Props> = ({
sorter={(a, b) => (moneyToNumber(a.balance)) - (moneyToNumber(b.balance))}
sortDirections={["ascend", "descend"]}
sortOrder={currentSortInfo.field === "balance" ? currentSortInfo.order : null}
render={(b: Money) => moneyToString(b) + t(p("unit")) }
render={(b: Money) => moneyToString(b) + t(p("unit"))}
/>
<Table.Column<AdminAccountInfo>
dataIndex="blockThresholdAmount"
title={(
<Space>
{ t(pCommon("blockThresholdAmount"))}
{t(pCommon("blockThresholdAmount"))}
<Tooltip title={t(p("blockThresholdAmountTooltip"))}>
<ExclamationCircleOutlined />
</Tooltip>
Expand All @@ -300,7 +303,7 @@ export const AccountTable: React.FC<Props> = ({
width="7%"
title={(
<Space>
{ t(p("status"))}
{t(p("status"))}
<Popover
title={t(p("statusTooltip"))}
content={(
Expand All @@ -326,7 +329,8 @@ export const AccountTable: React.FC<Props> = ({
<Tag color={s === DisplayedAccountState.DISPLAYED_NORMAL ? "green" : "red"}>
{DisplayedStateI18nTexts[s]}
</Tag>
); }
);
}
}
/>
<Table.Column<AdminAccountInfo>
Expand Down
Loading

0 comments on commit 4ab2cec

Please sign in to comment.