diff --git a/react-ui/config/routes.ts b/react-ui/config/routes.ts
index b2c41f14..a45883ab 100644
--- a/react-ui/config/routes.ts
+++ b/react-ui/config/routes.ts
@@ -345,7 +345,6 @@ export default [
},
],
},
-
{
name: '应用开发',
path: '/appsDeployment',
@@ -498,6 +497,18 @@ export default [
},
],
},
+ {
+ name: '算力积分',
+ path: '/points',
+ routes: [
+ {
+ name: '算力积分',
+ path: '',
+ key: 'points',
+ component: './Points/index',
+ },
+ ],
+ },
{
path: '*',
layout: false,
diff --git a/react-ui/public/fonts/DingTalk-JinBuTi.ttf b/react-ui/public/fonts/DingTalk-JinBuTi.ttf
new file mode 100644
index 00000000..c4efa55a
Binary files /dev/null and b/react-ui/public/fonts/DingTalk-JinBuTi.ttf differ
diff --git a/react-ui/public/fonts/DingTalk-JinBuTi.woff b/react-ui/public/fonts/DingTalk-JinBuTi.woff
new file mode 100644
index 00000000..5a8efa8e
Binary files /dev/null and b/react-ui/public/fonts/DingTalk-JinBuTi.woff differ
diff --git a/react-ui/public/fonts/DingTalk-JinBuTi.woff2 b/react-ui/public/fonts/DingTalk-JinBuTi.woff2
new file mode 100644
index 00000000..c8d272a5
Binary files /dev/null and b/react-ui/public/fonts/DingTalk-JinBuTi.woff2 differ
diff --git a/react-ui/public/fonts/TaoBaoMaiCaiTi-Regular.otf b/react-ui/public/fonts/TaoBaoMaiCaiTi-Regular.otf
new file mode 100644
index 00000000..21ba9622
Binary files /dev/null and b/react-ui/public/fonts/TaoBaoMaiCaiTi-Regular.otf differ
diff --git a/react-ui/public/fonts/TaoBaoMaiCaiTi-Regular.ttf b/react-ui/public/fonts/TaoBaoMaiCaiTi-Regular.ttf
new file mode 100644
index 00000000..31ab5e30
Binary files /dev/null and b/react-ui/public/fonts/TaoBaoMaiCaiTi-Regular.ttf differ
diff --git a/react-ui/public/fonts/TaoBaoMaiCaiTi-Regular.woff b/react-ui/public/fonts/TaoBaoMaiCaiTi-Regular.woff
new file mode 100644
index 00000000..0abc0f0e
Binary files /dev/null and b/react-ui/public/fonts/TaoBaoMaiCaiTi-Regular.woff differ
diff --git a/react-ui/public/fonts/TaoBaoMaiCaiTi-Regular.woff2 b/react-ui/public/fonts/TaoBaoMaiCaiTi-Regular.woff2
new file mode 100644
index 00000000..f4433e2e
Binary files /dev/null and b/react-ui/public/fonts/TaoBaoMaiCaiTi-Regular.woff2 differ
diff --git a/react-ui/public/fonts/font.css b/react-ui/public/fonts/font.css
index ea5ffc5c..06af2fdb 100644
--- a/react-ui/public/fonts/font.css
+++ b/react-ui/public/fonts/font.css
@@ -1,5 +1,23 @@
@font-face {
- font-family: Alibaba;
- src: url('./ALIBABA-PUHUITI-MEDIUM.TTF');
- font-display: swap;
- }
\ No newline at end of file
+ font-family: Alibaba;
+ src: url('./ALIBABA-PUHUITI-MEDIUM.TTF');
+ font-display: swap;
+}
+
+@font-face {
+ font-family: 'TaoBaoMaiCaiTi';
+ src: url('./TaoBaoMaiCaiTi-Regular.woff2') format('woff2'), /* 最优先使用 woff2 */
+ url('./TaoBaoMaiCaiTi-Regular.woff') format('woff'), /* 兼容性较好的 woff */
+ url('./TaoBaoMaiCaiTi-Regular.ttf') format('truetype'), /* ttf 作为备选 */
+ url('./TaoBaoMaiCaiTi-Regular.otf') format('opentype'); /* otf 作为最后选项 */
+ font-display: swap; /* 优化页面加载时的字体显示 */
+}
+
+
+@font-face {
+ font-family: 'DingTalk-JinBuTi';
+ src: url('./DingTalk-JinBuTi.woff2') format('woff2'), /* 最优先使用 woff2 */
+ url('./DingTalk-JinBuTi.woff') format('woff'), /* 兼容性较好的 woff */
+ url('./DingTalk-JinBuTi.ttf') format('truetype'); /* ttf 作为备选 */
+ font-display: swap; /* 优化页面加载时的字体显示 */
+}
\ No newline at end of file
diff --git a/react-ui/src/assets/img/user-points-bg.png b/react-ui/src/assets/img/user-points-bg.png
new file mode 100644
index 00000000..3f25b128
Binary files /dev/null and b/react-ui/src/assets/img/user-points-bg.png differ
diff --git a/react-ui/src/assets/img/workspace-experiment.png b/react-ui/src/assets/img/workspace-experiment.png
index bcd69981..0bca4327 100644
Binary files a/react-ui/src/assets/img/workspace-experiment.png and b/react-ui/src/assets/img/workspace-experiment.png differ
diff --git a/react-ui/src/assets/img/workspace-pipeline.png b/react-ui/src/assets/img/workspace-pipeline.png
index fbbc3ed7..f551cb9c 100644
Binary files a/react-ui/src/assets/img/workspace-pipeline.png and b/react-ui/src/assets/img/workspace-pipeline.png differ
diff --git a/react-ui/src/pages/Points/components/Statistics/index.less b/react-ui/src/pages/Points/components/Statistics/index.less
new file mode 100644
index 00000000..4ca97f96
--- /dev/null
+++ b/react-ui/src/pages/Points/components/Statistics/index.less
@@ -0,0 +1,31 @@
+.statistics {
+ display: flex;
+ align-items: center;
+ width: 100%;
+ padding: 20px 0;
+ background-color: @background-color;
+ border-radius: 8px;
+
+ &__item {
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+ align-items: center;
+
+ &--border {
+ border-right: 1px solid @border-color;
+ }
+
+ &__value {
+ margin-bottom: 8px;
+ color: @text-color;
+ font-weight: bold;
+ font-size: 30px;
+ }
+
+ &__title {
+ color: #999999;
+ font-size: @font-size-input;
+ }
+ }
+}
diff --git a/react-ui/src/pages/Points/components/Statistics/index.tsx b/react-ui/src/pages/Points/components/Statistics/index.tsx
new file mode 100644
index 00000000..e979b99d
--- /dev/null
+++ b/react-ui/src/pages/Points/components/Statistics/index.tsx
@@ -0,0 +1,38 @@
+import classNames from 'classnames';
+import styles from './index.less';
+
+type StatisticsProps = {
+ remaining?: number;
+ consuming?: number;
+};
+
+function Statistics({ remaining, consuming }: StatisticsProps) {
+ const items = [
+ {
+ title: '当前可用算力积分(分)',
+ value: remaining ?? '-',
+ },
+ {
+ title: '总消耗算力积分(分)',
+ value: consuming ?? '-',
+ },
+ ];
+
+ return (
+
+ {items.map((item, index) => (
+
+ {item.value}
+ {item.title}
+
+ ))}
+
+ );
+}
+
+export default Statistics;
diff --git a/react-ui/src/pages/Points/index.less b/react-ui/src/pages/Points/index.less
new file mode 100644
index 00000000..e97785e2
--- /dev/null
+++ b/react-ui/src/pages/Points/index.less
@@ -0,0 +1,19 @@
+.points-detail {
+ height: 100%;
+ &__content {
+ height: calc(100% - 60px);
+ margin-top: 10px;
+ padding: 20px 30px 0;
+ background-color: white;
+ border-radius: 10px;
+
+ &__top {
+ width: 100%;
+ }
+
+ &__table {
+ height: calc(100% - 117px - 28px);
+ margin-top: 28px;
+ }
+ }
+}
diff --git a/react-ui/src/pages/Points/index.tsx b/react-ui/src/pages/Points/index.tsx
new file mode 100644
index 00000000..20843820
--- /dev/null
+++ b/react-ui/src/pages/Points/index.tsx
@@ -0,0 +1,256 @@
+/*
+ * @Author: 赵伟
+ * @Date: 2024-04-16 13:58:08
+ * @Description: 模型部署服务列表
+ */
+import PageTitle from '@/components/PageTitle';
+import { getPointsConsumptionReq, getPointsStatisticsReq } from '@/services/points';
+import themes from '@/styles/theme.less';
+import { to } from '@/utils/promise';
+import statusTableCell from '@/utils/statusTableCell';
+import tableCellRender, { TableCellValueType } from '@/utils/table';
+import { Link } from '@umijs/max';
+import { Table, type TablePaginationConfig, type TableProps } from 'antd';
+import classNames from 'classnames';
+import { useEffect, useState } from 'react';
+import Statistics from './components/Statistics';
+import styles from './index.less';
+
+enum TaskType {
+ DevEnvironment = 'dev_environment',
+ Workflow = 'workflow',
+ Ray = 'ray',
+ Service = 'service',
+}
+
+const taskTypeOptions = [
+ {
+ value: 'dev_environment',
+ label: '开发环境',
+ },
+ {
+ value: 'workflow',
+ label: '实验',
+ },
+ {
+ value: 'ray',
+ label: '超参数自动寻优',
+ },
+ {
+ value: 'service',
+ label: '服务',
+ },
+];
+
+export type PointsData = {
+ computing_resource_id: number;
+ credit_per_hour: number; // 每小时消耗的积分
+ deduce_credit: number;
+ deduce_last_time: string;
+ description: string;
+ id: number;
+ node_id: string;
+ start_time: string;
+ state: number;
+ workflow_id?: number; // 流水线id
+ task_id: number; // 实验id
+ task_ins_id: number; // 实例id
+ task_type: string;
+ user_id: number;
+};
+
+export type PointsStatistics = {
+ deduceCredit: number;
+ userCredit: number;
+};
+
+// 格式化任务
+const formatTask = (value: string, record: PointsData) => {
+ let url;
+ switch (record.task_type) {
+ case TaskType.DevEnvironment:
+ url = `/developmentEnvironment`;
+ break;
+ case TaskType.Workflow:
+ if (record.workflow_id && record.task_ins_id) {
+ url = `/pipeline/experiment/instance/${record.workflow_id}/${record.task_ins_id}`;
+ }
+ break;
+ case TaskType.Ray:
+ if (record.task_id && record.task_ins_id) {
+ url = `/pipeline/hyperparameter/instance/${record.task_id}/${record.task_ins_id}`;
+ }
+ break;
+ case TaskType.Service:
+ if (record.task_id && record.task_ins_id) {
+ url = `/dataset/modelDeployment/serviceInfo/${record.task_id}/versionInfo/${record.task_ins_id}`;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (url) {
+ return {value};
+ } else {
+ return {value};
+ }
+};
+
+function PointsDetail() {
+ const [tableData, setTableData] = useState([]);
+ const [total, setTotal] = useState(0);
+ const [statistics, setStatistics] = useState();
+ const [pagination, setPagination] = useState({
+ current: 1,
+ pageSize: 10,
+ });
+
+ useEffect(() => {
+ // 获取积分统计
+ const getPointsStatistics = async () => {
+ const [res] = await to(getPointsStatisticsReq());
+ if (res && res.data) {
+ setStatistics(res.data);
+ }
+ };
+
+ getPointsStatistics();
+ }, []);
+
+ useEffect(() => {
+ // 获取积分消费明细
+ const getPointsConsumption = async () => {
+ const params: Record = {
+ page: pagination.current! - 1,
+ size: pagination.pageSize,
+ };
+ const [res] = await to(getPointsConsumptionReq(params));
+ if (res && res.data) {
+ const { content = [], totalElements = 0 } = res.data;
+ setTableData(content);
+ setTotal(totalElements);
+ }
+ };
+
+ getPointsConsumption();
+ }, [pagination]);
+
+ // 分页切换
+ const handleTableChange: TableProps['onChange'] = (
+ pagination,
+ _filters,
+ _sorter,
+ { action },
+ ) => {
+ if (action === 'paginate') {
+ setPagination(pagination);
+ }
+ };
+
+ const columns: TableProps['columns'] = [
+ {
+ title: '序号',
+ dataIndex: 'index',
+ key: 'index',
+ width: 80,
+ render: tableCellRender(false, TableCellValueType.Index, {
+ page: pagination.current! - 1,
+ pageSize: pagination.pageSize!,
+ }),
+ },
+ {
+ title: '任务',
+ dataIndex: 'task_name',
+ key: 'task_name',
+ width: '15%',
+ render: formatTask,
+ },
+ {
+ title: '任务类型',
+ dataIndex: 'task_type',
+ key: 'task_type',
+ width: '10%',
+ render: statusTableCell(taskTypeOptions),
+ },
+ {
+ title: '积分/小时',
+ dataIndex: 'credit_per_hour',
+ key: 'credit_per_hour',
+ width: '10%',
+ render: tableCellRender(),
+ },
+ {
+ title: '消耗的积分(分)',
+ dataIndex: 'deduce_credit',
+ key: 'deduce_credit',
+ width: '12%',
+ render: tableCellRender(),
+ },
+ {
+ title: '描述',
+ dataIndex: 'description',
+ key: 'description',
+ render: tableCellRender(true),
+ },
+ {
+ title: '开始时间',
+ dataIndex: 'start_time',
+ key: 'start_time',
+ width: '15%',
+ render: tableCellRender(false, TableCellValueType.Date),
+ },
+ {
+ title: '状态',
+ dataIndex: 'state',
+ key: 'state',
+ width: '8%',
+ render: statusTableCell([
+ {
+ value: 0,
+ label: '已结束',
+ color: themes['textColor'],
+ },
+ {
+ value: 1,
+ label: '进行中',
+ color: themes['primaryColor'],
+ },
+ ]),
+ },
+ ];
+
+ return (
+
+
+
+
+
+
+
+
`共${total}条`,
+ }}
+ onChange={handleTableChange}
+ rowKey="id"
+ />
+
+
+
+ );
+}
+
+export default PointsDetail;
diff --git a/react-ui/src/pages/System/User/edit.tsx b/react-ui/src/pages/System/User/edit.tsx
index dd23b6e0..3c8f045b 100644
--- a/react-ui/src/pages/System/User/edit.tsx
+++ b/react-ui/src/pages/System/User/edit.tsx
@@ -2,6 +2,7 @@ import { DictValueEnumObj } from '@/components/DictTag';
import KFModal from '@/components/KFModal';
import {
ProForm,
+ ProFormDigit,
ProFormRadio,
ProFormSelect,
ProFormText,
@@ -64,6 +65,7 @@ const UserForm: React.FC = (props) => {
remark: props.values.remark,
gitLinkUsername: props.values.gitLinkUsername,
gitLinkPassword: props.values.gitLinkPassword,
+ credit: props.values.credit,
});
}, [form, props, statusOptions]);
@@ -219,12 +221,7 @@ const UserForm: React.FC = (props) => {
autoComplete: 'new-password',
}}
allowClear
- rules={[
- {
- required: true,
- message: ,
- },
- ]}
+ rules={props.values.userId ? [] : [{ required: true, message: '请输入密码!' }]}
/>
= (props) => {
}}
rules={props.values.userId ? [] : [{ required: true, message: '请输入 Git 密码!' }]}
/>
+
{
dataIndex: 'phonenumber',
valueType: 'text',
},
+ {
+ title: ,
+ dataIndex: 'credit',
+ valueType: 'text',
+ },
{
title: ,
dataIndex: 'status',
diff --git a/react-ui/src/pages/Workspace/components/ExperimentChart/index.less b/react-ui/src/pages/Workspace/components/ExperimentChart/index.less
index a723c650..3af052da 100644
--- a/react-ui/src/pages/Workspace/components/ExperimentChart/index.less
+++ b/react-ui/src/pages/Workspace/components/ExperimentChart/index.less
@@ -1,4 +1,5 @@
.experiment-chart {
+ flex: none;
width: 295px;
min-width: 295px;
height: 140px;
diff --git a/react-ui/src/pages/Workspace/components/ExperimentTable/index.less b/react-ui/src/pages/Workspace/components/ExperimentTable/index.less
index fc83b21d..4b692883 100644
--- a/react-ui/src/pages/Workspace/components/ExperimentTable/index.less
+++ b/react-ui/src/pages/Workspace/components/ExperimentTable/index.less
@@ -1,8 +1,8 @@
.experiment-table {
flex: 1;
- min-width: 500px;
+ min-width: 378px;
height: 140px;
- padding: 12px 24px;
+ padding: 12px;
background: @workspace-background;
border-radius: 4px;
@@ -32,15 +32,15 @@
}
&__status {
- width: 20%;
+ width: 15%;
}
&__duration {
- width: 30%;
+ width: 25%;
}
&__date {
- width: calc(50% - 60px);
+ width: calc(60% - 60px);
}
&__operation {
diff --git a/react-ui/src/pages/Workspace/components/TotalStatistics/index.less b/react-ui/src/pages/Workspace/components/TotalStatistics/index.less
index d8943328..0fdef0b0 100644
--- a/react-ui/src/pages/Workspace/components/TotalStatistics/index.less
+++ b/react-ui/src/pages/Workspace/components/TotalStatistics/index.less
@@ -1,16 +1,12 @@
.total-statistics {
display: flex;
align-items: center;
- justify-content: center;
- width: 400px;
height: 140px;
- background: @workspace-background;
- border-radius: 4px;
+ padding: 0 16px;
&__icon {
- width: 85px;
- height: 80px;
- margin-right: 40px;
+ width: 63px;
+ margin-right: 15px;
}
&__title {
@@ -20,18 +16,10 @@
font-size: @font-size-content;
}
- &__title-shadow {
- position: absolute;
- bottom: 6px;
- left: 0;
- width: 79px;
- height: 6px;
- background: linear-gradient(87.07deg, rgba(22, 100, 255, 0.6) 0%, rgba(22, 100, 255, 0) 100%);
- }
-
&__count {
color: @text-color;
font-weight: 700;
font-size: 25px;
+ font-family: DingTalk-JinBuTi;
}
}
diff --git a/react-ui/src/pages/Workspace/components/TotalStatistics/index.tsx b/react-ui/src/pages/Workspace/components/TotalStatistics/index.tsx
index c6834cfb..ef7f79de 100644
--- a/react-ui/src/pages/Workspace/components/TotalStatistics/index.tsx
+++ b/react-ui/src/pages/Workspace/components/TotalStatistics/index.tsx
@@ -1,3 +1,4 @@
+import { Flex } from 'antd';
import styles from './index.less';
type TotalStatisticsProps = {
@@ -11,13 +12,12 @@ function TotalStatistics({ icon = '', title = '', count = 0, style }: TotalStati
return (

-
+
);
}
diff --git a/react-ui/src/pages/Workspace/components/UserPoints/index.less b/react-ui/src/pages/Workspace/components/UserPoints/index.less
new file mode 100644
index 00000000..4a7554bf
--- /dev/null
+++ b/react-ui/src/pages/Workspace/components/UserPoints/index.less
@@ -0,0 +1,36 @@
+.user-points {
+ display: flex;
+ flex: none;
+ flex-direction: column;
+ align-items: center;
+
+ width: 326px;
+ height: 228px;
+ .backgroundFullImage(url(@/assets/img/user-points-bg.png));
+
+ &__label {
+ margin-top: 60px;
+ color: @text-color;
+ font-size: @font-size-title;
+ font-family: DingTalk-JinBuTi;
+ }
+
+ &__value {
+ margin-top: 8px;
+ margin-bottom: 12px;
+ color: @primary-color;
+ font-size: 36px;
+ font-family: DingTalk-JinBuTi;
+ line-height: 43px;
+ }
+
+ &__button {
+ padding: 8px 20px;
+ color: @primary-color;
+ font-size: @font-size-content;
+ background: rgba(255, 255, 255, 0.3);
+ border: 1px solid #ffffff;
+ border-radius: 8px;
+ cursor: pointer;
+ }
+}
diff --git a/react-ui/src/pages/Workspace/components/UserPoints/index.tsx b/react-ui/src/pages/Workspace/components/UserPoints/index.tsx
new file mode 100644
index 00000000..3ea37e23
--- /dev/null
+++ b/react-ui/src/pages/Workspace/components/UserPoints/index.tsx
@@ -0,0 +1,40 @@
+import { PointsStatistics } from '@/pages/Points/index';
+import { getPointsStatisticsReq } from '@/services/points';
+import { to } from '@/utils/promise';
+import { useNavigate } from '@umijs/max';
+import { useEffect, useState } from 'react';
+import styles from './index.less';
+
+function UserPoints() {
+ const [statistics, setStatistics] = useState();
+ const navigate = useNavigate();
+
+ useEffect(() => {
+ // 获取积分统计
+ const getPointsStatistics = async () => {
+ const [res] = await to(getPointsStatisticsReq());
+ if (res && res.data) {
+ setStatistics(res.data);
+ }
+ };
+
+ getPointsStatistics();
+ }, []);
+
+ return (
+
+
当前可用算力积分
+
{statistics?.userCredit ?? '--'}
+
{
+ navigate('/points');
+ }}
+ >
+ 查看详情
+
+
+ );
+}
+
+export default UserPoints;
diff --git a/react-ui/src/pages/Workspace/index.less b/react-ui/src/pages/Workspace/index.less
index 3fbcc8e8..d498e652 100644
--- a/react-ui/src/pages/Workspace/index.less
+++ b/react-ui/src/pages/Workspace/index.less
@@ -6,6 +6,7 @@
background: linear-gradient(#ecf2fe, #f9fafb);
&__overview {
+ flex: 1;
gap: 15px;
margin-bottom: 16px;
padding: 20px 30px;
@@ -21,11 +22,19 @@
&__content {
display: flex;
+
+ flex-wrap: wrap;
gap: 15px;
align-items: center;
- @media screen and (max-width: 1800px) {
- flex-wrap: wrap;
+ &__statistics {
+ flex: none;
+ background: linear-gradient(
+ 123.08deg,
+ rgba(138, 138, 138, 0.06) 1.32%,
+ rgba(22, 100, 255, 0.02) 58.35%
+ );
+ border-radius: 4px;
}
}
}
diff --git a/react-ui/src/pages/Workspace/index.tsx b/react-ui/src/pages/Workspace/index.tsx
index 691ca550..efda7e70 100644
--- a/react-ui/src/pages/Workspace/index.tsx
+++ b/react-ui/src/pages/Workspace/index.tsx
@@ -2,6 +2,7 @@ import { useDraggable } from '@/hooks/draggable';
import { getWorkspaceOverviewReq } from '@/services/workspace';
import { ExperimentInstance } from '@/types';
import { to } from '@/utils/promise';
+import { Divider, Flex } from 'antd';
import { useEffect, useState } from 'react';
import Draggable from 'react-draggable';
import AssetsManagement from './components/AssetsManagement';
@@ -10,6 +11,7 @@ import ExperitableTable from './components/ExperimentTable';
import QuickStart from './components/QuickStart';
import RobotFrame from './components/RobotFrame';
import TotalStatistics from './components/TotalStatistics';
+import UserPoints from './components/UserPoints';
import UserSpace from './components/UserSpace';
import WorkspaceIntro from './components/WorkspaceIntro';
import styles from './index.less';
@@ -28,6 +30,7 @@ function Workspace() {
setRobotFrameVisible((prev) => !prev),
);
const users: number[] = new Array(8).fill(0);
+
useEffect(() => {
getWorkspaceOverview();
}, []);
@@ -43,27 +46,38 @@ function Workspace() {
return (
-
-
运行概览
-
-
-
-
- {overviewData?.experimentInsStatus && (
-
- )}
+
+
+
运行概览
+
+
+
+
+
+
+
+
+ {overviewData?.experimentInsStatus && (
+
+ )}
+
-
+
+
diff --git a/react-ui/src/services/points/index.ts b/react-ui/src/services/points/index.ts
new file mode 100644
index 00000000..6b5cc0d4
--- /dev/null
+++ b/react-ui/src/services/points/index.ts
@@ -0,0 +1,22 @@
+/*
+ * @Author: 赵伟
+ * @Date: 2025-03-20 13:48:53
+ * @Description: 积分
+ */
+
+import { request } from '@umijs/max';
+
+// 分页查询积分消费明细
+export function getPointsConsumptionReq(params: any) {
+ return request(`/api/mmp/computingResource/resouceOccupy`, {
+ method: 'GET',
+ params,
+ });
+}
+
+// 分页查询积分消费明细
+export function getPointsStatisticsReq() {
+ return request(`/api/mmp/computingResource/credit`, {
+ method: 'GET',
+ });
+}
diff --git a/react-ui/src/styles/theme.less b/react-ui/src/styles/theme.less
index d044889f..89b955c8 100644
--- a/react-ui/src/styles/theme.less
+++ b/react-ui/src/styles/theme.less
@@ -69,6 +69,14 @@
-webkit-line-clamp: @line;
}
+// 背景
+.backgroundFullImage(@url) {
+ background-image: @url;
+ background-repeat: no-repeat;
+ background-position: top center;
+ background-size: 100% 100%;
+}
+
// 导出变量
:export {
primaryColor: @primary-color;
diff --git a/react-ui/src/types/system/user.d.ts b/react-ui/src/types/system/user.d.ts
index a74ee0e8..0eca095a 100644
--- a/react-ui/src/types/system/user.d.ts
+++ b/react-ui/src/types/system/user.d.ts
@@ -21,6 +21,7 @@ declare namespace API.System {
remark: string;
gitLinkUsername?: string;
gitLinkPassword?: string;
+ credit?: number;
}
export interface UserListParams {
diff --git a/react-ui/src/utils/statusTableCell.tsx b/react-ui/src/utils/statusTableCell.tsx
new file mode 100644
index 00000000..8efa5803
--- /dev/null
+++ b/react-ui/src/utils/statusTableCell.tsx
@@ -0,0 +1,23 @@
+/*
+ * @Author: 赵伟
+ * @Date: 2025-03-20 14:33:01
+ * @Description: 通用的 Table 状态单元格
+ */
+
+export type StatusInfo = {
+ value: number | string;
+ label: string;
+ color?: string;
+};
+
+function statusTableCell(infos: StatusInfo[]) {
+ return function (status?: string | number | null) {
+ const info = infos.find((item) => item.value === status);
+ if (status === null || status === undefined || !info) {
+ return --;
+ }
+ return {info.label};
+ };
+}
+
+export default statusTableCell;
diff --git a/react-ui/src/utils/table.tsx b/react-ui/src/utils/table.tsx
index 1a1e84c4..757471fe 100644
--- a/react-ui/src/utils/table.tsx
+++ b/react-ui/src/utils/table.tsx
@@ -1,7 +1,7 @@
/*
* @Author: 赵伟
* @Date: 2024-06-26 10:05:52
- * @Description: Table cell 自定义 render
+ * @Description: Table Cell 自定义 render
*/
import { isEmpty } from '@/utils';