Compare commits

...

2 Commits

Author SHA1 Message Date
IsAurora6
118eb0af80 feat: Optimize the display of payment products. (#5115) 2026-02-16 16:32:02 +08:00
Yang Luo
c16aebe642 fix: update README slogan 2026-02-16 02:33:45 +08:00
3 changed files with 24 additions and 53 deletions

View File

@@ -1,5 +1,5 @@
<h1 align="center" style="border-bottom: none;">📦⚡️ Casdoor</h1>
<h3 align="center">An open-source UI-first Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML, CAS, LDAP, SCIM, WebAuthn, TOTP, MFA and RADIUS</h3>
<h3 align="center">An open-source AI-first Identity and Access Management (IAM) /AI MCP gateway and auth server with web UI supporting MCP, A2A, OAuth 2.1, OIDC, SAML, CAS, LDAP, SCIM, WebAuthn, TOTP, MFA, Face ID, Google Workspace, Azure AD</h3>
<p align="center">
<a href="#badge">
<img alt="semantic-release" src="https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg">

View File

@@ -18,7 +18,6 @@ import {InfoCircleTwoTone} from "@ant-design/icons";
import * as PaymentBackend from "./backend/PaymentBackend";
import * as Setting from "./Setting";
import i18next from "i18next";
import * as ProductBackend from "./backend/ProductBackend";
const {Option} = Select;
@@ -30,7 +29,6 @@ class PaymentEditPage extends React.Component {
organizationName: props.organizationName !== undefined ? props.organizationName : props.match.params.organizationName,
paymentName: props.match.params.paymentName,
payment: null,
products: [],
isModalVisible: false,
isInvoiceLoading: false,
mode: props.location.mode !== undefined ? props.location.mode : "edit",
@@ -39,7 +37,6 @@ class PaymentEditPage extends React.Component {
UNSAFE_componentWillMount() {
this.getPayment();
this.getProducts();
}
getPayment() {
@@ -58,19 +55,6 @@ class PaymentEditPage extends React.Component {
});
}
getProducts() {
ProductBackend.getProducts(this.state.organizationName)
.then((res) => {
if (res.status === "ok") {
this.setState({
products: res.data,
});
} else {
Setting.showMessage("error", `Failed to get products: ${res.msg}`);
}
});
}
goToViewOrder() {
const payment = this.state.payment;
if (payment && payment.order) {
@@ -240,29 +224,6 @@ class PaymentEditPage extends React.Component {
}} />
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("general:Products"), i18next.t("payment:Products - Tooltip"))} :
</Col>
<Col span={22} >
<Select
mode="multiple"
style={{width: "100%"}}
value={this.state.payment?.products || []}
disabled={isViewMode}
allowClear
options={(this.state.products || [])
.map((p) => ({
label: Setting.getLanguageText(p?.displayName) || p?.name,
value: p?.name,
}))
.filter((o) => o.value)}
onChange={(value) => {
this.updatePaymentField("products", value);
}}
/>
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("order:Price"), i18next.t("plan:Price - Tooltip"))} :

View File

@@ -14,7 +14,7 @@
import React from "react";
import {Link} from "react-router-dom";
import {Button, List, Table, Tooltip} from "antd";
import {Button, Col, List, Row, Table, Tooltip} from "antd";
import moment from "moment";
import * as Setting from "./Setting";
import * as PaymentBackend from "./backend/PaymentBackend";
@@ -195,21 +195,31 @@ class PaymentListPage extends BaseListPage {
paddingBottom: 8,
}}
renderItem={(productInfo, i) => {
const price = productInfo.price * (productInfo.quantity || 1);
const price = productInfo.price || 0;
const number = productInfo.quantity || 1;
const currency = record.currency || "USD";
const productName = productInfo.displayName || productInfo.name;
return (
<List.Item>
<div style={{display: "inline"}}>
<Tooltip placement="topLeft" title={i18next.t("general:Edit")}>
<Button style={{marginRight: "5px"}} icon={<EditOutlined />} size="small" onClick={() => Setting.goToLinkSoft(this, `/products/${record.owner}/${productInfo.name}`)} />
</Tooltip>
<Link to={`/products/${record.owner}/${productInfo.name}`}>
{productInfo.displayName || productInfo.name}
</Link>
<span style={{marginLeft: "8px", color: "#666"}}>
{Setting.getPriceDisplay(price, currency)}
</span>
</div>
<Row style={{width: "100%"}} wrap={false} gutter={[12, 0]}>
<Col flex="auto" style={{minWidth: 0}}>
<div style={{display: "flex", alignItems: "center", minWidth: 0}}>
<Tooltip placement="topLeft" title={i18next.t("general:Edit")}>
<Button style={{marginRight: "5px"}} icon={<EditOutlined />} size="small" onClick={() => Setting.goToLinkSoft(this, `/products/${record.owner}/${productInfo.name}`)} />
</Tooltip>
<Tooltip placement="topLeft" title={productName}>
<Link to={`/products/${record.owner}/${productInfo.name}`} style={{display: "inline-block", maxWidth: "100%", minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap"}}>
{productName}
</Link>
</Tooltip>
</div>
</Col>
<Col flex="none" style={{whiteSpace: "nowrap"}}>
<span style={{color: "#666"}}>
{Setting.getCurrencySymbol(currency)}{price} ({Setting.getCurrencyText(currency)}) × {number}
</span>
</Col>
</Row>
</List.Item>
);
}}