feat: for redeem.mcsmanager.com

This commit is contained in:
YuMao 2025-01-21 16:53:00 +08:00
parent 0ba3e32abc
commit 1748fcd751
11 changed files with 72 additions and 28 deletions

View File

@ -72,6 +72,9 @@ const handleSubmit = async () => {
:label="t('TXT_CODE_c38813a8')"
:rules="[{ required: true, message: t('TXT_CODE_2695488c') }]"
>
<a-typography-paragraph type="secondary">
{{ t("TXT_CODE_b90e9abd") }}
</a-typography-paragraph>
<a-input
v-model:value="formData.username"
name="mcsm-redeem-username"
@ -93,9 +96,6 @@ const handleSubmit = async () => {
</a-form-item>
<div class="text-center flex justify-center">
<div>
<a-typography-paragraph type="secondary">
{{ t("TXT_CODE_b90e9abd") }}
</a-typography-paragraph>
<div class="flex justify-center">
<a-button
class="w-28"

View File

@ -3,6 +3,7 @@ import { computed, onMounted, ref, type Ref } from "vue";
import { queryUsername } from "./user";
import { Modal } from "ant-design-vue";
import { t } from "@/lang/i18n";
import { useAppStateStore } from "@/stores/useAppStateStore";
export interface ShopItem {
productId: number;
@ -71,8 +72,9 @@ export const requestRedeemPlatform = useDefineApi<
export function useShopInfo() {
const config = requestRedeemPlatform();
const isError = ref<Error>();
const { state: appState } = useAppStateStore();
onMounted(async () => {
const loadProducts = async (businessId?: string) => {
try {
isError.value = undefined;
await config.execute({
@ -80,18 +82,25 @@ export function useShopInfo() {
targetUrl: "/api/instances/query_products",
method: "GET",
params: {
addr: CURRENT_PANEL_ADDR
addr: CURRENT_PANEL_ADDR,
businessId: businessId || appState.settings.businessId
}
}
});
} catch (error) {
isError.value = error as Error;
}
};
onMounted(async () => {
await loadProducts();
});
return {
...config,
isError,
loadProducts,
isLoading: config.isLoading,
state: config.state as Ref<ShopInfoResponse>,
shopInfo: computed<ShopInfo>(() => config.state.value?.ispInfo),
products: computed<ShopItem[]>(() => config.state.value?.products)
@ -99,6 +108,7 @@ export function useShopInfo() {
}
export function useRedeem() {
const { state: appState } = useAppStateStore();
const { execute, isLoading } = requestRedeemPlatform();
const preCheckUsername = (username: string) => {
@ -135,7 +145,7 @@ export function useRedeem() {
data: {
targetUrl: "/api/instances/use_redeem",
method: "POST",
data: { code, username }
data: { code, username, businessId: appState.settings.businessId }
}
});
return res.value as BuyInstanceResponse;
@ -146,7 +156,7 @@ export function useRedeem() {
data: {
targetUrl: "/api/instances/use_redeem",
method: "POST",
data: { code, instanceId, username }
data: { code, instanceId, username, businessId: appState.settings.businessId }
}
});
return res.value as BuyInstanceResponse;
@ -157,7 +167,7 @@ export function useRedeem() {
data: {
targetUrl: "/api/instances/purchase_history",
method: "GET",
params: { code }
params: { code, businessId: appState.settings.businessId }
}
});
return res.value as PurchaseQueryResponse;

View File

@ -21,7 +21,8 @@ export const useAppStateStore = createGlobalState(() => {
settings: {
canFileManager: false,
allowUsePreset: false,
businessMode: false
businessMode: false,
businessId: ""
}
});

View File

@ -75,6 +75,7 @@ export interface Settings {
redisUrl: string;
allowUsePreset: boolean;
businessMode: boolean;
businessId: string;
}
export interface ImageInfo {
@ -244,5 +245,6 @@ export interface PanelStatus {
canFileManager: boolean;
allowUsePreset: boolean;
businessMode: boolean;
businessId: string;
};
}

View File

@ -41,7 +41,7 @@ interface MySettings extends Settings {
bgUrl?: string;
}
const ApacheLicense = `Copyright 2024 MCSManager Dev
const ApacheLicense = `Copyright ${new Date().getFullYear()} MCSManager Dev
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -398,7 +398,10 @@ onMounted(async () => {
{{ t("TXT_CODE_e5b7522d") }}
</a-typography-text>
</a-typography-paragraph>
<a-select v-model:value.prop="formData.canFileManager" style="max-width: 320px">
<a-select
v-model:value.prop="(formData as any).canFileManager"
style="max-width: 320px"
>
<a-select-option
v-for="item in allYesNo"
:key="item.value"
@ -418,7 +421,10 @@ onMounted(async () => {
{{ t("TXT_CODE_f5f9664") }}
</a-typography-text>
</a-typography-paragraph>
<a-select v-model:value.prop="formData.allowUsePreset" style="max-width: 320px">
<a-select
v-model:value.prop="(formData as any).allowUsePreset"
style="max-width: 320px"
>
<a-select-option
v-for="item in allYesNo"
:key="item.value"
@ -439,7 +445,10 @@ onMounted(async () => {
</a-typography-text>
</a-typography-paragraph>
<a-select v-model:value.prop="formData.crossDomain" style="max-width: 320px">
<a-select
v-model:value.prop="(formData as any).crossDomain"
style="max-width: 320px"
>
<a-select-option
v-for="item in allYesNo"
:key="item.value"
@ -461,7 +470,7 @@ onMounted(async () => {
</a-typography-paragraph>
<a-select
v-model:value.prop="formData.reverseProxyMode"
v-model:value.prop="(formData as any).reverseProxyMode"
style="max-width: 320px"
>
<a-select-option
@ -484,7 +493,10 @@ onMounted(async () => {
</a-typography-text>
</a-typography-paragraph>
<a-select v-model:value.prop="formData.loginCheckIp" style="max-width: 320px">
<a-select
v-model:value.prop="(formData as any).loginCheckIp"
style="max-width: 320px"
>
<a-select-option
v-for="item in allYesNo"
:key="item.value"
@ -527,7 +539,7 @@ onMounted(async () => {
<a-switch v-model:checked="formData.businessMode" @change="submit(false)" />
</div>
</div>
<div>
<div class="mb-24">
<a-typography-paragraph>
<a-typography-title :level="5">
{{ t("TXT_CODE_d31196db") }}
@ -537,15 +549,31 @@ onMounted(async () => {
</a-typography-text>
</a-typography-paragraph>
<div>
<a-button
type="primary"
:disabled="!formData.businessMode"
@click="gotoBusinessCenter()"
>
<a-button :disabled="!formData.businessMode" @click="gotoBusinessCenter()">
{{ t("TXT_CODE_2dbd3cd3") }}
</a-button>
</div>
</div>
<div v-if="formData.businessMode" class="mb-24">
<a-typography-paragraph>
<a-typography-title :level="5">节点ID</a-typography-title>
<a-typography-text type="secondary">
商家控制台 - 节点列表 中可以找到节点ID
</a-typography-text>
</a-typography-paragraph>
<div>
<a-input
v-model:value="formData.businessId"
style="max-width: 200px"
placeholder="eg: 123"
/>
</div>
</div>
<div>
<a-button type="primary" :loading="submitIsLoading" @click="submit(false)">
保存
</a-button>
</div>
</div>
</template>

View File

@ -8,7 +8,6 @@ import { t } from "@/lang/i18n";
import { useShopInfo } from "@/services/apis/redeem";
import { useAppStateStore } from "@/stores/useAppStateStore";
import type { LayoutCard } from "@/types";
defineProps<{
card: LayoutCard;
}>();
@ -56,6 +55,7 @@ const openLoginPage = () => {
<div v-if="isLoading">
<Loading />
</div>
<div v-if="shopItems" class="shop-item-container">
<div class="flex justify-end mb-20" style="gap: 10px">
<a-button type="primary" @click="openDialog">
@ -90,8 +90,8 @@ const openLoginPage = () => {
<div>
<div class="shelves-card-item-price-label">{{ t("TXT_CODE_4bf8a52f") }}</div>
<div>
<span class="price-text"> {{ item.price }} </span
><span>/{{ t("TXT_CODE_6cb9bb04") }}</span>
<span class="price-text"> {{ item.price }} </span>
<span>/{{ t("TXT_CODE_6cb9bb04") }}</span>
</div>
</div>
</div>

View File

@ -1996,7 +1996,7 @@
"TXT_CODE_ef27fda1": "售后渠道:",
"TXT_CODE_ec0b25f5": "您可以将此页面地址复制通过互联网分享给用户,用户无需登录即可访问此页面。",
"TXT_CODE_e5bf0df1": "暂时无法获取商家信息,可能服务器正在维护中,请稍后再稍后再尝试!",
"TXT_CODE_4ef3f800": "如果您是商家,请留 https://redeem.mcsmanager.com 或官网网站的公告以获取帮助。",
"TXT_CODE_4ef3f800": "如果您是商家,请留 https://redeem.mcsmanager.com 或官网网站的公告以获取帮助。",
"TXT_CODE_aa43b248": "进入控制台",
"TXT_CODE_4770de17": "商家信息",
"TXT_CODE_381f8f22": "商品列表",

View File

@ -55,4 +55,6 @@ export default class SystemConfig {
// to sell instances based on redeem
// (this feature may not be available in some countries)
businessMode = false;
businessId = "";
}

View File

@ -78,7 +78,8 @@ router.all(
settings: {
canFileManager: systemConfig?.canFileManager || false,
allowUsePreset: systemConfig?.allowUsePreset || false,
businessMode: systemConfig?.businessMode || false
businessMode: systemConfig?.businessMode || false,
businessId: systemConfig?.businessId || null
} as Partial<SystemConfig>
};
}

View File

@ -52,6 +52,7 @@ router.put("/setting", permission({ level: ROLE.ADMIN }), async (ctx) => {
if (config.allowUsePreset != null) systemConfig.allowUsePreset = Boolean(config.allowUsePreset);
if (config.presetPackAddr != null) systemConfig.presetPackAddr = String(config.presetPackAddr);
if (config.businessMode != null) systemConfig.businessMode = Boolean(config.businessMode);
if (config.businessId != null) systemConfig.businessId = String(config.businessId);
if (config.language != null) {
logger.warn($t("TXT_CODE_e29a9317"), config.language);
systemConfig.language = String(config.language);

View File

@ -10,8 +10,7 @@ import type { IGlobalInstanceConfig } from "common/global";
// A commercial platform for selling instances released by the MCSManager Dev Team.
// Currently, it only supports some countries and regions.
// If you do not turn on "Commercial Mode", MCSManager will not send any data.
export const REDEEM_PLATFORM_ADDR = "http://localhost:5174";
// export const REDEEM_PLATFORM_ADDR = "https://redeem.mcsmanager.com";
export const REDEEM_PLATFORM_ADDR = "https://redeem.mcsmanager.com";
// ------- Protocol Define -------
export interface INodeStatusProtocol {