From 6d1bb9039da8ea7a4762afd31345538804471156 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=AC=A2=E4=B9=90=E9=A9=AC?=
<38058090+SkywalkerSpace@users.noreply.github.com>
Date: Fri, 17 May 2024 11:14:55 +0800
Subject: [PATCH] Subscription (#6069)
* subscription api
* subscription page
* subscriptionAPI.js
* buy quota
* add currency icons
---------
Co-authored-by: Michael An <2331806369@qq.com>
---
frontend/config/webpack.entry.js | 1 +
frontend/src/assets/icons/currency.svg | 1 +
frontend/src/components/common/account.js | 7 +
frontend/src/components/subscription.js | 523 ++++++++++++++++++
frontend/src/css/subscription.css | 230 ++++++++
frontend/src/pages/org-admin/index.js | 2 +
.../src/pages/org-admin/org-subscription.js | 32 ++
frontend/src/pages/org-admin/side-panel.js | 11 +-
frontend/src/subscription.js | 72 +++
frontend/src/utils/constants.js | 1 +
frontend/src/utils/subscription-api.js | 61 ++
media/css/seahub_react.css | 1 +
media/img/qr-sale.png | Bin 0 -> 97467 bytes
seahub/api2/endpoints/admin/organizations.py | 30 +
seahub/api2/endpoints/admin/users.py | 27 +-
seahub/api2/endpoints/subscription.py | 132 +++++
seahub/api2/views.py | 3 +-
.../organizations/org_admin_react.html | 2 +
seahub/organizations/urls.py | 2 +
seahub/organizations/views.py | 2 +
seahub/settings.py | 1 +
seahub/subscription/__init__.py | 0
seahub/subscription/settings.py | 10 +
seahub/subscription/urls.py | 7 +
seahub/subscription/utils.py | 90 +++
seahub/subscription/views.py | 91 +++
seahub/templates/base_for_react.html | 1 +
seahub/templates/subscription/pay_result.html | 8 +
.../subscription/subscription_react.html | 19 +
seahub/urls.py | 15 +-
30 files changed, 1377 insertions(+), 5 deletions(-)
create mode 100644 frontend/src/assets/icons/currency.svg
create mode 100644 frontend/src/components/subscription.js
create mode 100644 frontend/src/css/subscription.css
create mode 100644 frontend/src/pages/org-admin/org-subscription.js
create mode 100644 frontend/src/subscription.js
create mode 100644 frontend/src/utils/subscription-api.js
create mode 100644 media/img/qr-sale.png
create mode 100644 seahub/api2/endpoints/subscription.py
create mode 100644 seahub/subscription/__init__.py
create mode 100644 seahub/subscription/settings.py
create mode 100644 seahub/subscription/urls.py
create mode 100644 seahub/subscription/utils.py
create mode 100644 seahub/subscription/views.py
create mode 100644 seahub/templates/subscription/pay_result.html
create mode 100644 seahub/templates/subscription/subscription_react.html
diff --git a/frontend/config/webpack.entry.js b/frontend/config/webpack.entry.js
index 4f4b1eb78a6..9b88e763b90 100644
--- a/frontend/config/webpack.entry.js
+++ b/frontend/config/webpack.entry.js
@@ -38,6 +38,7 @@ const entryFiles = {
sysAdmin: '/pages/sys-admin',
search: '/pages/search',
uploadLink: '/pages/upload-link',
+ subscription: '/subscription.js',
};
const getEntries = (isEnvDevelopment) => {
diff --git a/frontend/src/assets/icons/currency.svg b/frontend/src/assets/icons/currency.svg
new file mode 100644
index 00000000000..23bc368565e
--- /dev/null
+++ b/frontend/src/assets/icons/currency.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/src/components/common/account.js b/frontend/src/components/common/account.js
index 1f991c1b567..379e3d52250 100644
--- a/frontend/src/components/common/account.js
+++ b/frontend/src/components/common/account.js
@@ -6,6 +6,10 @@ import { seafileAPI } from '../../utils/seafile-api';
import { siteRoot, gettext, appAvatarURL, enableSSOToThirdpartWebsite } from '../../utils/constants';
import toaster from '../toast';
+const {
+ isOrgContext,
+} = window.app.pageOptions;
+
const propTypes = {
isAdminPanel: PropTypes.bool,
};
@@ -22,6 +26,7 @@ class Account extends Component {
isStaff: false,
isOrgStaff: false,
usageRate: '',
+ enableSubscription: false,
};
this.isFirstMounted = true;
}
@@ -81,6 +86,7 @@ class Account extends Component {
isInstAdmin: resp.data.is_inst_admin,
isOrgStaff: resp.data.is_org_staff === 1 ? true : false,
showInfo: !this.state.showInfo,
+ enableSubscription: resp.data.enable_subscription,
});
}).catch(error => {
let errMessage = Utils.getErrorMsg(error);
@@ -163,6 +169,7 @@ class Account extends Component {
{gettext('Settings')}
+ {(this.state.enableSubscription && !isOrgContext) && {'付费管理'}}
{this.renderMenu()}
{enableSSOToThirdpartWebsite && {gettext('Customer Portal')}}
{gettext('Log out')}
diff --git a/frontend/src/components/subscription.js b/frontend/src/components/subscription.js
new file mode 100644
index 00000000000..e1c00945bb0
--- /dev/null
+++ b/frontend/src/components/subscription.js
@@ -0,0 +1,523 @@
+import React, { Component, Fragment } from 'react';
+import PropTypes from 'prop-types';
+import toaster from './toast';
+import { Modal, ModalHeader, ModalBody, ModalFooter, InputGroup, InputGroupAddon, InputGroupText, Input, Button } from 'reactstrap';
+import { gettext, serviceURL } from '../utils/constants';
+import { Utils } from '../utils/utils';
+import { subscriptionAPI } from '../utils/subscription-api';
+import Loading from './loading';
+
+import '../css/layout.css';
+import '../css/subscription.css';
+
+const {
+ isOrgContext,
+} = window.app.pageOptions;
+
+
+const PlansPropTypes = {
+ plans: PropTypes.array.isRequired,
+ onPay: PropTypes.func.isRequired,
+ paymentType: PropTypes.string.isRequired,
+ handleContentScroll: PropTypes.func.isRequired,
+};
+
+class Plans extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ currentPlan: props.plans[0],
+ assetQuotaUnitCount: 1,
+ count: 1,
+ };
+ }
+
+ togglePlan = (plan) => {
+ this.setState({currentPlan: plan}, () => {
+ });
+ };
+
+ onPay = () => {
+ let { paymentType } = this.props;
+ let { currentPlan, assetQuotaUnitCount, count } = this.state;
+ let totalAmount, assetQuota, newUserCount;
+
+ // parse
+ if (paymentType === 'paid') {
+ newUserCount = currentPlan.count;
+ totalAmount = currentPlan.total_amount;
+ } else if (paymentType === 'extend_time') {
+ newUserCount = currentPlan.count;
+ assetQuota = currentPlan.asset_quota;
+ totalAmount = currentPlan.total_amount;
+ } else if (paymentType === 'add_user') {
+ newUserCount = count;
+ totalAmount = count * currentPlan.price_per_user;
+ } else if (paymentType === 'buy_quota') {
+ assetQuota = (assetQuotaUnitCount) * currentPlan.asset_quota_unit;
+ totalAmount = assetQuotaUnitCount * currentPlan.price_per_asset_quota_unit;
+ } else {
+ toaster.danger(gettext('Internal Server Error.'));
+ return;
+ }
+
+ this.props.onPay(currentPlan.plan_id, newUserCount, assetQuota, totalAmount);
+ };
+
+ onCountInputChange = (e) => {
+ let { currentPlan } = this.state;
+ if (!currentPlan.can_custom_count) {
+ return;
+ }
+ let count = e.target.value.replace(/^(0+)|[^\d]+/g, '');
+ if (count < 1) {
+ count = 1;
+ } else if (count > 9999) {
+ count = 9999;
+ }
+ this.setState({count: count});
+ };
+
+ onAssetQuotaUnitCountInputChange = (e) => {
+ let { currentPlan } = this.state;
+ if (!currentPlan.can_custom_asset_quota) {
+ return;
+ }
+ let count = e.target.value.replace(/^(0+)|[^\d]+/g, '');
+ if (count < 1) {
+ count = 1;
+ } else if (count > 9999) {
+ count = 9999;
+ }
+ this.setState({assetQuotaUnitCount: count});
+ };
+
+ renderPaidOrExtendTime = () => {
+ let { plans, paymentType } = this.props;
+ let { currentPlan } = this.state;
+ let boughtQuota = 0;
+ if (paymentType === 'extend_time') {
+ boughtQuota = currentPlan.asset_quota - 100;
+ }
+ let totalAmount = currentPlan.total_amount;
+ let originalTotalAmount = totalAmount;
+ return (
+
+
{'选择方案'}
+
+ {plans.map((item, index) => {
+ let selectedCss = item.plan_id === currentPlan.plan_id ? 'plan-selected' : '';
+ let countDescription = '¥' + item.price_per_user;
+ if (isOrgContext) {
+ countDescription += '/每用户';
+ }
+ return (
+ -
+ {item.name}
+ {countDescription}
+
+ );
+ })}
+
+
+ {paymentType === 'extend_time' && boughtQuota > 0 &&
+
+ {'增加空间'}
+
+ -
+ {currentPlan.asset_quota_unit + 'GB x ' + (boughtQuota / currentPlan.asset_quota_unit)}
+ {/* 续费时候需要减去附赠的100GB */}
+ {'¥' + (boughtQuota / currentPlan.asset_quota_unit) * currentPlan.price_per_asset_quota_unit}
+
+
+
+ }
+
+
{'方案汇总'}
+
+
+
-
+ {'所选方案'}
+ {currentPlan.name}
+
+ {isOrgContext &&
+ -
+ {'成员人数'}
+ {currentPlan.count + '人'}
+
+ }
+ -
+ {'可用空间'}
+ {'100GB(附赠)' + (boughtQuota > 0 ? '+' + boughtQuota + 'GB(扩充)' : '')}
+
+ -
+ {'到期时间'}
+ {currentPlan.new_term_end}
+
+ -
+ {'实际支付金额'}
+
+ {originalTotalAmount !== totalAmount &&
+ {'¥' + originalTotalAmount}
+ }
+ {'¥' + totalAmount + ' '}
+
+
+
+
+
+
+ );
+ };
+
+ renderAddUser = () => {
+ let { currentPlan, count } = this.state;
+ let operationIntro = '新增用户';
+ let originalTotalAmount = count * currentPlan.price_per_user;
+ let totalAmount = originalTotalAmount;
+ return (
+
+
+
{currentPlan.name}
+
+ {'¥ '}{currentPlan.price}{' ' + currentPlan.description}
+
+
+
+ {operationIntro}
+
+
+
+
+ {'总价 ¥ ' + totalAmount}
+ {originalTotalAmount !== totalAmount &&
+ {' ¥' + originalTotalAmount}
+ }
+
+
{'有效期至 ' + currentPlan.new_term_end}
+
{'注:当有效期剩余天数少于计划中的时候,增加用户的价格按天来计算'}
+
+
+ );
+ };
+
+ renderBuyQuota = () => {
+ let { currentPlan, assetQuotaUnitCount } = this.state;
+ let operationIntro = '新增空间';
+ let originalTotalAmount = assetQuotaUnitCount * currentPlan.price_per_asset_quota_unit;
+ let totalAmount = originalTotalAmount;
+ return (
+
+
+
{currentPlan.name}
+
+ {'¥ '}{currentPlan.asset_quota_price}{' ' + currentPlan.asset_quota_description}
+
+
+
+ {operationIntro}
+
+
+
+ {' x ' + currentPlan.asset_quota_unit + 'GB'}
+
+
+
+ {'总价 ¥ ' + totalAmount}
+ {originalTotalAmount !== totalAmount &&
+ {' ¥' + originalTotalAmount}
+ }
+
+
{'有效期至 ' + currentPlan.new_term_end}
+
{'注:当有效期剩余天数少于计划中的时候,增加空间的价格按天来计算'}
+
+
+ );
+ };
+
+ render() {
+ let { paymentType } = this.props;
+ if (paymentType === 'paid' || paymentType === 'extend_time') {
+ return this.renderPaidOrExtendTime();
+ } else if (paymentType === 'add_user') {
+ return this.renderAddUser();
+ } else if (paymentType === 'buy_quota') {
+ return this.renderBuyQuota();
+ } else {
+ toaster.danger(gettext('Internal Server Error.'));
+ return;
+ }
+ }
+}
+
+Plans.propTypes = PlansPropTypes;
+
+const PlansDialogPropTypes = {
+ isOrgContext: PropTypes.bool.isRequired,
+ paymentType: PropTypes.string.isRequired,
+ paymentTypeTrans: PropTypes.string.isRequired,
+ toggleDialog: PropTypes.func.isRequired,
+};
+
+class PlansDialog extends Component {
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ isLoading: true,
+ isWaiting: false,
+ planList: [],
+ paymentSourceList: [],
+ };
+ }
+
+ getPlans = () => {
+ subscriptionAPI.getSubscriptionPlans(this.props.paymentType).then((res) => {
+ this.setState({
+ planList: res.data.plan_list,
+ paymentSourceList: res.data.payment_source_list,
+ isLoading: false,
+ });
+ }).catch(error => {
+ let errorMsg = Utils.getErrorMsg(error);
+ this.setState({
+ isLoading: false,
+ errorMsg: errorMsg,
+ });
+ });
+ };
+
+ onPay = (planID, count, asset_quota, totalAmount) => {
+ this.setState({ isWaiting: true });
+ let payUrl = serviceURL + '/subscription/pay/?payment_source=' + this.state.paymentSourceList[0] +
+ '&payment_type=' + this.props.paymentType + '&plan_id=' + planID +
+ '&total_amount=' + totalAmount;
+ if (count) {
+ payUrl += '&count=' + count;
+ }
+ if (asset_quota) {
+ payUrl += '&asset_quota=' + asset_quota;
+ }
+ window.open(payUrl);
+ };
+
+ onReload = () => {
+ window.location.reload();
+ };
+
+ componentDidMount() {
+ this.getPlans();
+ }
+
+ render() {
+ const { isLoading, isWaiting, planList } = this.state;
+ const { toggleDialog, paymentTypeTrans, paymentType } = this.props;
+ const modalStyle = (paymentType === 'paid' || paymentType === 'extend_time') ?
+ {width: '560px', maxWidth: '560px'} : {width: '560px'};
+
+ if (isLoading) {
+ return (
+
+ {paymentTypeTrans}
+
+
+
+
+ );
+ }
+ if (isWaiting) {
+ return (
+
+ {paymentTypeTrans}
+
+ {'是否完成付款?'}
+
+
+
+
+
+ );
+ }
+ return (
+
+ {paymentTypeTrans}
+
+
+
+
+ );
+ }
+}
+
+PlansDialog.propTypes = PlansDialogPropTypes;
+
+const propTypes = {
+ isOrgContext: PropTypes.bool.isRequired,
+ handleContentScroll: PropTypes.func,
+};
+
+class Subscription extends Component {
+
+ constructor(props) {
+ super(props);
+ this.paymentTypeTransMap = {
+ paid: '立即购买',
+ extend_time: '立即续费',
+ add_user: '增加用户',
+ buy_quota: '增加空间',
+ };
+ this.state = {
+ isLoading: true,
+ errorMsg: '',
+ isDialogOpen: false,
+ planName: this.props.isOrgContext ? '团队版' : '个人版',
+ userLimit: 20,
+ assetQuota: 1,
+ termEnd: '长期',
+ subscription: null,
+ paymentTypeList: [],
+ currentPaymentType: '',
+ errorMsgCode: ''
+ };
+ }
+
+ getSubscription = () => {
+ subscriptionAPI.getSubscription().then((res) => {
+ const subscription = res.data.subscription;
+ const paymentTypeList = res.data.payment_type_list;
+ if (!subscription) {
+ this.setState({
+ isLoading: false,
+ paymentTypeList: paymentTypeList,
+ });
+ } else {
+ let isActive = subscription.is_active;
+ let plan = subscription.plan;
+ this.setState({
+ isLoading: false,
+ subscription,
+ planName: plan.name,
+ userLimit: subscription.user_limit,
+ assetQuota: isActive ? subscription.asset_quota : plan.asset_quota,
+ termEnd: isActive ? subscription.term_end : '已过期',
+ paymentTypeList: paymentTypeList,
+ });
+ }
+ }).catch(error => {
+ let errorMsg = Utils.getErrorMsg(error);
+ this.setState({
+ isLoading: false,
+ errorMsg: errorMsg,
+ });
+ });
+ };
+
+ toggleDialog = () => {
+ this.setState({ isDialogOpen: !this.state.isDialogOpen });
+ };
+
+ togglePaymentType = (paymentType) => {
+ this.setState({ currentPaymentType: paymentType });
+ this.toggleDialog();
+ };
+
+ componentDidMount() {
+ this.getSubscription();
+ }
+
+ render() {
+ const { isLoading, errorMsg, planName, userLimit, assetQuota, termEnd,
+ isDialogOpen, paymentTypeList, currentPaymentType } = this.state;
+ if (isLoading) {
+ return ;
+ }
+ if (errorMsg) {
+ return {errorMsg}
;
+ }
+ return (
+
+
+
+
{'当前版本'}
+
{planName}
+
+ {this.props.isOrgContext &&
+
+
{'用户数限制'}
+
{userLimit}
+
+ }
+
+
{'空间'}
+
{assetQuota ? assetQuota + 'GB' : '1GB'}
+
+
+
{'订阅有效期'}
+
{termEnd}
+
+
+ {paymentTypeList.map((item, index) => {
+ let name = this.paymentTypeTransMap[item];
+ return (
+
+ );
+ })}
+ {!this.state.subscription &&
+
+
{'销售咨询'}
+
+
{'微信扫码联系销售'}
+
+ }
+
+ {isDialogOpen &&
+
+ }
+
+ );
+ }
+}
+
+Subscription.propTypes = propTypes;
+
+export default Subscription;
diff --git a/frontend/src/css/subscription.css b/frontend/src/css/subscription.css
new file mode 100644
index 00000000000..7b02a0d57a2
--- /dev/null
+++ b/frontend/src/css/subscription.css
@@ -0,0 +1,230 @@
+.content {
+ padding: 0rem 1rem 8rem;
+ overflow: auto;
+ }
+
+ .content .dropdown .btn-outline-primary {
+ color: #f19645;
+ background-color: transparent;
+ background-image: none;
+ border-color: #f19645;
+ }
+
+ .content .dropdown .btn-outline-primary:hover {
+ color: #fff;
+ background-color: #f19645;
+ border-color: #f19645;
+ }
+
+ .content .dropdown .btn-outline-primary:focus {
+ box-shadow: 0 0 0 2px rgba(241, 150, 69, 0.5);
+ }
+
+ .content .dropdown .btn-outline-primary:active {
+ color: #fff;
+ background-color: #f19645;
+ border-color: #f19645;
+ }
+
+ .content .dropdown .btn-outline-primary:not(:disabled):not(.disabled):active:focus,
+ .content .dropdown .btn-outline-primary:not(:disabled):not(.disabled).active:focus,
+ .content .dropdown .show > .btn-outline-primary.dropdown-toggle:focus {
+ box-shadow: 0 0 0 2px rgba(241, 150, 69, 0.5);
+ }
+
+ .subscription-info {
+ margin: 1em 0 3em;
+ }
+
+ .subscription-info-heading {
+ font-size: 1rem;
+ font-weight: normal;
+ padding-bottom: 0.2em;
+ border-bottom: 1px solid #ddd;
+ margin-bottom: 0.7em;
+ }
+
+ .price-version-container-header {
+ max-width: 90%;
+ border-radius: 10px;
+ padding: 0 1rem 2rem;
+ box-shadow: 0 3px 8px 3px rgba(116, 129, 141, 0.15);
+ overflow: hidden;
+ margin: 0.5rem 1rem;
+ }
+
+ .price-version-container-header .price-version-container-top {
+ height: 10px;
+ margin: 0 -1rem;
+ }
+
+ .price-version-container-header .price-version-plan-name {
+ font-size: 1.5rem;
+ padding: 1rem 0;
+ border-bottom: 1px solid #ED7109;
+ }
+
+ .price-version-container-header .price-table-btn-details {
+ color: #fff;
+ font-size: 1rem;
+ }
+
+ .price-version-container-header .font-500 {
+ font-weight: 500;
+ }
+
+ .price-version-container-header .price-version-plan-price {
+ font-size: 2rem;
+ }
+
+ .price-version-container-header .price-version-plan-whole-price {
+ font-size: 24px;
+ }
+
+ .price-version-container-header .price-version-plan-valid-day,
+ .price-version-container-header .price-version-plan-user-number {
+ font-size: 18px;
+ }
+
+ .subscription-container {
+ width: 480px;
+ margin: 0.5rem auto;
+ }
+
+ .price-version-container-header .user-quota-plan-name {
+ margin-bottom: 24px;
+ text-align: center;
+ border-bottom: 1px solid rgba(253, 150, 68, 0.4);
+ }
+
+ .subscription-container .items-dl {
+ margin-top: 10px;
+ }
+
+ .plan-description-item {
+ border: 1px solid #bdbdbd;
+ border-radius: 5px;
+ margin: 0 0 10px;
+ display: flex;
+ justify-content: space-between;
+ background-color: #f9f9f9;
+ line-height: 3;
+ padding: 0 20px;
+ cursor: pointer;
+ }
+
+ .plan-description-item.plan-selected {
+ background-color: #fff5eb;
+ border-color: #ED7109;
+ border-width: 2px;
+ }
+
+ .plan-description-item .plan-name {
+ font-size: 20px;
+ font-weight: 500;
+ }
+
+ .plan-description-item .plan-description {
+ font-size: 20px;
+ font-weight: 500;
+ color: #ED7109;
+ }
+
+ .order-item {
+ margin: 0px;
+ display: flex;
+ justify-content: space-between;
+ border-left: 1px solid #bdbdbd;
+ border-right: 1px solid #bdbdbd;
+ background-color: #f9f9f9;
+ padding: 5px 20px;
+ line-height: 2;
+ }
+
+ .order-item.order-item-top {
+ border-top: 1px solid #bdbdbd;
+ border-radius: 5px 5px 0 0;
+ }
+
+ .order-item.order-item-middle {
+ border-bottom: 1px solid #bdbdbd;
+ }
+
+ .order-item.order-item-bottom {
+ border-bottom: 1px solid #bdbdbd;
+ border-radius: 0 0 5px 5px;
+ }
+
+ .order-item .order-into {
+ color: #666666;
+ }
+
+ .order-item .order-value {
+ font-weight: 500;
+ color: #000;
+ }
+
+ .order-item .order-value .input-group-append,
+ .order-item .order-value .input-group-prepend {
+ height: 38px;
+ }
+
+ .order-item .order-price {
+ font-size: 26px;
+ font-weight: 500;
+ color: #ED7109;
+ }
+
+ .order-item .order-price span:first-child {
+ font-size: 16px;
+ }
+
+ .subscription-submit {
+ background-color: #ED7109;
+ border-radius: 5px;
+ width: 100%;
+ margin-bottom: 10px;
+ color: white;
+ height: 44px;
+ font-size: 16px;
+ }
+
+ .subscription-notice {
+ font-size: 14px;
+ color: #9a9a9a;
+ }
+
+ .subscription-container .subscription-subtitle {
+ font-size: 18px;
+ font-weight: 500;
+ }
+
+ .subscription-container .subscription-list.order-item-top.order-item-bottom {
+ border-radius: 5px;
+ }
+
+ .subscription-container .subscription-list span {
+ height: 36px;
+ line-height: 36px;
+ }
+
+ .subscription-container .text-orange {
+ color: #ED7109 !important;
+ }
+
+ .user-numbers.input-group .input-group-prepend {
+ width: 50%;
+ }
+
+ .space-quota .input-group .input-group-append,
+ .space-quota .input-group .input-group-prepend {
+ width: 33.33%;
+ }
+
+ .subscription-add-space .input-group .input-group-append .input-group-text,
+ .price-version-container-header .input-group .input-group-prepend .input-group-text {
+ width: 100%;
+ text-align: center;
+ font-weight: 500;
+ display: block;
+ }
diff --git a/frontend/src/pages/org-admin/index.js b/frontend/src/pages/org-admin/index.js
index 7ac17290e7d..e38f133fe31 100644
--- a/frontend/src/pages/org-admin/index.js
+++ b/frontend/src/pages/org-admin/index.js
@@ -36,6 +36,7 @@ import OrgLogsFileAudit from './org-logs-file-audit';
import OrgLogsFileUpdate from './org-logs-file-update';
import OrgLogsPermAudit from './org-logs-perm-audit';
import OrgSAMLConfig from './org-saml-config';
+import OrgSubscription from './org-subscription';
import '../../css/layout.css';
import '../../css/toolbar.css';
@@ -96,6 +97,7 @@ class Org extends React.Component {
+
diff --git a/frontend/src/pages/org-admin/org-subscription.js b/frontend/src/pages/org-admin/org-subscription.js
new file mode 100644
index 00000000000..6006f585520
--- /dev/null
+++ b/frontend/src/pages/org-admin/org-subscription.js
@@ -0,0 +1,32 @@
+import React, { Component, Fragment } from 'react';
+import PropTypes from 'prop-types';
+import MainPanelTopbar from './main-panel-topbar';
+import Subscription from '../../components/subscription';
+
+const propTypes = {
+ onCloseSidePanel: PropTypes.func,
+};
+
+class OrgSubscription extends Component {
+ render() {
+ return (
+
+
+
+
+ );
+ }
+}
+
+OrgSubscription.propTypes = propTypes;
+
+export default OrgSubscription;
diff --git a/frontend/src/pages/org-admin/side-panel.js b/frontend/src/pages/org-admin/side-panel.js
index 0946548e6b5..b19273caffe 100644
--- a/frontend/src/pages/org-admin/side-panel.js
+++ b/frontend/src/pages/org-admin/side-panel.js
@@ -2,7 +2,8 @@ import React from 'react';
import PropTypes from 'prop-types';
import { Link } from '@gatsbyjs/reach-router';
import Logo from '../../components/logo';
-import { gettext, siteRoot, enableMultiADFS } from '../../utils/constants';
+import Icon from '../../components/icon';
+import { gettext, siteRoot, enableSubscription, enableMultiADFS } from '../../utils/constants';
const propTypes = {
isSidePanelClosed: PropTypes.bool.isRequired,
@@ -80,6 +81,14 @@ class SidePanel extends React.Component {
{gettext('Departments')}
+ {enableSubscription &&
+
+ this.tabItemClick('subscription')} >
+
+ {'付费管理'}
+
+
+ }
this.tabItemClick('publinkadmin')} >
diff --git a/frontend/src/subscription.js b/frontend/src/subscription.js
new file mode 100644
index 00000000000..8c5177163d9
--- /dev/null
+++ b/frontend/src/subscription.js
@@ -0,0 +1,72 @@
+import React from 'react';
+import ReactDOM from 'react-dom';
+import { siteRoot, mediaUrl, logoPath, logoWidth, logoHeight, siteTitle } from './utils/constants';
+import SideNav from './components/user-settings/side-nav';
+import Account from './components/common/account';
+import Notification from './components/common/notification';
+import Subscription from './components/subscription';
+
+import './css/toolbar.css';
+import './css/search.css';
+import './css/user-settings.css';
+
+
+class UserSubscription extends React.Component {
+
+ constructor(props) {
+ super(props);
+ this.sideNavItems = [
+ { show: true, href: '#current-plan', text: '当前版本' },
+ { show: true, href: '#asset-quota', text: '空间' },
+ { show: true, href: '#current-subscription-period', text: '订阅有效期' },
+ { show: true, href: '#product-price', text: '云服务付费方案' },
+ ];
+ this.state = {
+ curItemID: this.sideNavItems[0].href.substr(1),
+ };
+ }
+
+ handleContentScroll = (e) => {
+ // Mobile does not display the sideNav, so when scrolling don't update curItemID
+ const scrollTop = e.target.scrollTop;
+ const scrolled = this.sideNavItems.filter((item, index) => {
+ return item.show && document.getElementById(item.href.substr(1)).offsetTop - 45 < scrollTop;
+ });
+ if (scrolled.length) {
+ this.setState({
+ curItemID: scrolled[scrolled.length - 1].href.substr(1)
+ });
+ }
+ };
+
+ render() {
+ let logoUrl = logoPath.startsWith('http') ? logoPath : mediaUrl + logoPath;
+ return (
+
+ );
+ }
+}
+
+ReactDOM.render(
+ ,
+ document.getElementById('wrapper')
+);
diff --git a/frontend/src/utils/constants.js b/frontend/src/utils/constants.js
index 3a461c64fa9..0bb26943f1f 100644
--- a/frontend/src/utils/constants.js
+++ b/frontend/src/utils/constants.js
@@ -140,6 +140,7 @@ export const orgEnableAdminCustomLogo = window.org ? window.org.pageOptions.orgE
export const orgEnableAdminCustomName = window.org ? window.org.pageOptions.orgEnableAdminCustomName === 'True' : false;
export const orgEnableAdminInviteUser = window.org ? window.org.pageOptions.orgEnableAdminInviteUser === 'True' : false;
export const enableMultiADFS = window.org ? window.org.pageOptions.enableMultiADFS === 'True' : false;
+export const enableSubscription = window.org ? window.org.pageOptions.enableSubscription : false;
// sys admin
export const constanceEnabled = window.sysadmin ? window.sysadmin.pageOptions.constance_enabled : '';
diff --git a/frontend/src/utils/subscription-api.js b/frontend/src/utils/subscription-api.js
new file mode 100644
index 00000000000..9a45cd7a651
--- /dev/null
+++ b/frontend/src/utils/subscription-api.js
@@ -0,0 +1,61 @@
+import axios from 'axios';
+import cookie from 'react-cookies';
+import { siteRoot } from './constants';
+
+class SubscriptionAPI {
+
+ init({ server, username, password, token }) {
+ this.server = server;
+ this.username = username;
+ this.password = password;
+ this.token = token; //none
+ if (this.token && this.server) {
+ this.req = axios.create({
+ baseURL: this.server,
+ headers: { 'Authorization': 'Token ' + this.token },
+ });
+ }
+ return this;
+ }
+
+ initForSeahubUsage({ siteRoot, xcsrfHeaders }) {
+ if (siteRoot && siteRoot.charAt(siteRoot.length - 1) === '/') {
+ var server = siteRoot.substring(0, siteRoot.length - 1);
+ this.server = server;
+ } else {
+ this.server = siteRoot;
+ }
+
+ this.req = axios.create({
+ headers: {
+ 'X-CSRFToken': xcsrfHeaders,
+ }
+ });
+ return this;
+ }
+
+ getSubscription() {
+ const url = this.server + '/api/v2.1/subscription/';
+ return this.req.get(url);
+ }
+
+ getSubscriptionPlans(paymentType) {
+ const url = this.server + '/api/v2.1/subscription/plans/';
+ let params = {
+ payment_type: paymentType,
+ };
+ return this.req.get(url, { params: params });
+ }
+
+ getSubscriptionLogs() {
+ const url = this.server + '/api/v2.1/subscription/logs/';
+ return this.req.get(url);
+ }
+
+}
+
+let subscriptionAPI = new SubscriptionAPI();
+let xcsrfHeaders = cookie.load('sfcsrftoken');
+subscriptionAPI.initForSeahubUsage({ siteRoot, xcsrfHeaders });
+
+export { subscriptionAPI };
diff --git a/media/css/seahub_react.css b/media/css/seahub_react.css
index 648d24e7d48..cc819859d4d 100644
--- a/media/css/seahub_react.css
+++ b/media/css/seahub_react.css
@@ -668,6 +668,7 @@ a, a:hover { color: #ec8000; }
color: #fff;
}
+.side-nav-con .seafile-multicolor-icon,
.side-nav-con [class^="sf2-icon-"],
.side-nav-con [class^="sf3-font-"],
.side-nav-con [class^="fas"] {
diff --git a/media/img/qr-sale.png b/media/img/qr-sale.png
new file mode 100644
index 0000000000000000000000000000000000000000..e986c08b1c6c64f91a7f72bf157ff01ef2d9099f
GIT binary patch
literal 97467
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