Commit 94333785 authored by 王勇霞's avatar 王勇霞

feat: 调整

parent c7524f25
This diff is collapsed.
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="theme-color" content="#000000" />
<link rel="dns-prefetch" href="//yun.duiba.com.cn" />
<link rel="preconnect" href="//embedlog.duiba.com.cn">
<link rel="preconnect" href="//embedlog.duiba.com.cn" />
<title>活动标题</title>
<script type="text/javascript">
if (localStorage && localStorage.isWebp) {
document
.getElementsByTagName('html')[0]
.setAttribute('duiba-webp', 'true');
}
if (localStorage && localStorage.isWebp) {
document.getElementsByTagName("html")[0].setAttribute("duiba-webp", "true");
}
</script>
<script src="//yun.duiba.com.cn/spark/v2/spark.base.fz.wxpollyfill.js"></script>
<script src="//yun.duiba.com.cn/js-libs/rem/1.1.3/rem.min.js"></script>
<script src="//yun.duiba.com.cn/h5/lib/zepto.min.js"></script>
<!-- 华夏银行app文件 -->
<script src="//yun.duiba.com.cn/polaris/hxbExtLib.min.f2e3022c5ce5dd92689bff0a5b6c5cb0e9193cd1.js"></script>
<script>
var CFG = CFG || {};
CFG.projectId = location.pathname.split('/')[2] || '1';
function getUrlParam(name) {
var search = window.location.search;
var matched = search
.slice(1)
.match(new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i'));
return search.length ? matched && matched[2] : null;
}
CFG.appID = '${APPID}';
if (!getUrlParam("appID")) {
// alert("【警告】检测到活动url中没有appID参数\n缺少该参数会导致埋点、分享、app信息获取错误。")
}
var CFG = CFG || {};
CFG.projectId = location.pathname.split("/")[2] || "1";
function getUrlParam(name) {
var search = window.location.search;
var matched = search.slice(1).match(new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i"));
return search.length ? matched && matched[2] : null;
}
CFG.appID = "${APPID}";
if (!getUrlParam("appID")) {
// alert("【警告】检测到活动url中没有appID参数\n缺少该参数会导致埋点、分享、app信息获取错误。")
}
</script>
</head>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<body>
<noscript> You need to enable JavaScript to run this app. </noscript>
<div id="root"></div>
<!--
This HTML file is a template.
......@@ -52,7 +47,5 @@
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
\ No newline at end of file
</body>
</html>
import API from "@src/api";
import {
setCookieId
} from "@src/api/utils";
/** 渠道 */
export const CHANNEL = {
/** 华夏理财 */
HXLC: "1",
/** 母行-华夏银行 */
HXBANK: "2",
/** 渠道5-昆仑银行 */
KUNLUN: "5",
};
/**
* 普通跳转客服
* 注意:小程序需要额外增加业务域名 https://duiba.qiyukf.com/
*/
export function jumpService() {
location.href = location.origin + '/faq/index'
location.href = location.origin + "/faq/index";
}
/** 跳转行方页面-华夏理财 */
export function hxlcAppJump(fundcode) {
const navBarStyle = { backgroundColor: "#d20a10" };
const target =
// eslint-disable-next-line @spark/best-practices/no-url-in-js
"gmu://web?startPage=" +
encodeURIComponent(`index.html#/fund-detail?fundcode=${fundcode}&from=third`) +
`&navBarType=2&navBarStyle=${encodeURIComponent(JSON.stringify(navBarStyle))}`;
console.info("目标地址=================>:", target);
window.location.href = target;
}
export function appJump(url, hideNavbar = false, data = {}) {
API.tempSaveCookie().then((res) => {
if (res?.data) {
localStorage.setItem("db_temp_cookie", res.data);
// setCookieId(res.data);
}
}).finally(() => {
// 判断jsbridge加载完成
function ready(callback) {
if (window.AlipayJSBridge) {
callback && callback();
} else {
document.addEventListener("AlipayJSBridgeReady", callback, false);
}
}
// app对应跳转方法
window.MarsJSBridge.invoke("pushPage", {
uri: url,
data,
pageParams: {
hideNavbar,
}
});
function bfSearchMenu(param, callback) {
window.AlipayJSBridge.call(
"BFSearchMenuHandler",
{
param: param,
},
callback
);
}
/** 行方跳转方法-华夏银行 */
export function appJump(url) {
console.info("bfSearchMenu url", url);
// 判断端内,若在端内走回调
ready(() => {
// 跳转的路径,视具体修改
bfSearchMenu({
url,
});
});
}
/** 跳转方法 区分app */
export function diffJump(url) {
if (CFG.channel == CHANNEL.HXLC) {
// 华夏理财
hxlcAppJump(url);
} else if (CFG.channel == CHANNEL.HXBANK) {
// 华夏银行
appJump(url);
} else {
// 其他三方app
location.href = url;
}
}
......@@ -15,15 +15,16 @@ MD();
import LoadingDemo from "@src/pages/LoadingDemo/LoadingDemo";
import ActualHome from "@src/pages/ActualHome/index";
import PrizePage from "@src/pages/PrizePage";
import DetailPage from "@src/pages/DetailPage";
import { PAGE_MAP } from "./utils/constants";
/**
* 所有页面场景
*/
const pageMap = {
[PAGE_MAP.LOADING_PAGE]: <LoadingDemo />,
[PAGE_MAP.ACTUAL_HOME_PAGE]: <ActualHome />,
[PAGE_MAP.PRIZE_PAGE]: <PrizePage />,
[PAGE_MAP.PRODUCT_DETAIL]: <DetailPage />,
};
@observer
......
......@@ -10,7 +10,7 @@
-webkit-user-select: text;
}
*:not(input,textarea) {
*:not(input, textarea) {
-webkit-touch-callout: none;
-webkit-user-select: none;
}
......@@ -42,7 +42,6 @@ body {
overflow: hidden;
}
.com_Container {
width: 100%;
height: 100%;
......
{"preLoadImg":[],"asyncLoadImg":["ActualHome/bg.png","ActualHome/financeAchievement.png","ActualHome/newUserGift.png","ActualHome/prize.png","ActualHome/rule.png","ActualHome/sign_bg.png","ActualHome/sign_btn.png","ActualHome/sign_ok.png","ActualHome/sign_task.png","ActualHome/sign_task_title.png","ActualHome/sign_wait.png","Common/close.png","LoadingPage/loadingBg.jpg","LoadingPage/loadingFill.png","LoadingPage/loadingIp.png","Pop/BlackListPop/bg.png","Pop/BlackListPop/btn_actual.png","Pop/BlackListPop/title_actual.png","Pop/RulePop/bg.png"]}
\ No newline at end of file
{"preLoadImg":[],"asyncLoadImg":["ActualHome/bg.png","ActualHome/financeAchievement.png","ActualHome/newUserGift.png","ActualHome/prize.png","ActualHome/rule.png","ActualHome/sign_bg.png","ActualHome/sign_btn.png","ActualHome/sign_ok.png","ActualHome/sign_task.png","ActualHome/sign_task_title.png","ActualHome/sign_wait.png","ActualHome/tab1_bg.png","ActualHome/tab2_bg.png","Common/close.png","LoadingPage/loadingBg.jpg","LoadingPage/loadingFill.png","LoadingPage/loadingIp.png","Pop/BlackListPop/bg.png","Pop/BlackListPop/btn_actual.png","Pop/BlackListPop/title_actual.png","Pop/RulePop/bg.png","PrizePage/back.png","PrizePage/bg.png","PrizePage/empty_img.png","PrizePage/item_btn_bg.png","PrizePage/item_btn_bg2.png"]}
\ No newline at end of file
import React from "react";
import { observer } from "mobx-react";
import { Button } from "@src/components/Button";
import SignModule from "@src/pages/components/SignModule/index";
import RankModule from "@src/pages/components/RankModule/index";
import BannerModule from "@src/pages/components/BannerModule/index";
import SignModule from "@src/pages/components/SignModule";
import RankModule from "@src/pages/components/RankModule";
import BannerModule from "@src/pages/components/BannerModule";
import ProductListModule from "@src/pages/components/ProductListModule";
import "./index.less";
import modalStore from "@src/store/modal";
import { _throttle } from "@src/utils/utils";
......@@ -28,25 +29,32 @@ class ActualHome extends React.Component {
render() {
return (
<div className="actual-home-page">
{/* 规格&奖品 */}
<Button className="rule-icon" onClick={this.openRule}></Button>
<Button className="prize-icon" onClick={this.goPrize}></Button>
<div className="com_Container">
<div className="actual-home-page">
{/* 规格&奖品 */}
<Button className="rule-icon" onClick={this.openRule}></Button>
<Button className="prize-icon" onClick={this.goPrize}></Button>
{/* 其他icon */}
<Button className="new-user-gift-icon"></Button>
<Button className="finance-achievement-icon"></Button>
{/* 其他icon */}
<Button className="new-user-gift-icon"></Button>
<Button className="finance-achievement-icon"></Button>
{/* 排行榜 */}
<RankModule />
{/* 排行榜 */}
<RankModule />
{/* 真实持仓 */}
{/* 真实持仓 */}
{/* banner区 */}
<BannerModule />
{/* banner区 */}
<BannerModule />
{/* 签到 */}
<SignModule />
{/* 签到 */}
<SignModule />
{/* 产品列表 */}
<ProductListModule />
<div style={{ height: "90px" }}></div>
</div>
</div>
);
}
......
......@@ -7,6 +7,7 @@
background-size: 750px 779px;
background-color: #e86a3c;
box-sizing: border-box;
overflow-y: scroll;
}
.rule-icon {
......
import React from "react";
import { observer } from "mobx-react";
import "./index.less";
// import { Button, Toast } from "@grace/ui";
import { motion } from "framer-motion";
import classNames from "classnames";
import API from "@src/api";
import { _throttle } from "@src/utils/utils";
import { PAGE_MAP } from "@src/utils/constants";
import { Button } from "@src/components/Button";
import modalStore from "@src/store/modal";
import modal from "@src/store";
import hxLink from "hx-product_detail-link";
// import { diffJump } from "@src/AppTool";
const EOpType = {
Buy: "buy",
Sell: "sell",
};
@observer
class DetailPage extends React.Component {
state = {
tabType: EOpType.Buy,
productName: "",
totalProfit: 0,
tranche: 0,
marketValue: 0,
yesterdayProfit: 0,
availableFunds: 0,
minBuyLimit: 0,
sellInput: "",
buyInput: "",
iframeUrl: "",
};
async componentDidMount() {
this.getFrameUrl();
this.updateInfo();
}
getFrameUrl = () => {
// 1912121000101
hxLink({ fundcode: this.props.code }).then((res) => {
this.setState({
iframeUrl: res.path,
});
});
};
async updateInfo() {
const { success, data } = await API.mncpIndex({ code: this.props.code });
if (!success) return;
this.setState({
productName: data.productName,
totalProfit: data.totalProfit,
tranche: data.tranche,
marketValue: data.marketValue,
yesterdayProfit: data.yesterdayProfit,
availableFunds: data.availableFunds,
minBuyLimit: data.minBuyLimit,
buyInput: data.availableFunds / 100,
});
}
clickTab = (type) => {
this.setState({
tabType: type,
});
};
clickSimulateBuy = _throttle(async () => {
const { buyInput } = this.state;
console.log(buyInput);
if (!+buyInput || buyInput.toString().trim() === "") {
// Toast.show("请输入买入金额");
return;
}
// +(+xxx * 100).toFixed(0) 解决精度问题 比如76.9*100=7690.000000000001 而不是7690
if (+(+buyInput * 100).toFixed(0) < this.state.minBuyLimit) {
// Toast.show("低于起购价");
return;
}
const div = +(+buyInput * 100).toFixed(0) / this.state.minBuyLimit;
if (div !== Math.floor(div)) {
// Toast.show("按起购倍数递增哦~");
return;
}
if (+(+buyInput * 100).toFixed(0) > this.state.availableFunds) {
// Toast.show("超出买入上限啦");
return;
}
modalStore.pushPop("BuyPanel");
// ModalCtrl.showModal(BuyPanel, {
// name: this.state.productName,
// amount: buyInput,
// call: async () => {
// const { success } = await API.buy({ code: this.props.code, amount: +(+buyInput * 100).toFixed(0) });
// this.updateInfo();
// if (!success) return;
// Toast.show("购买成功");
// },
// });
});
clickReallyBuy = _throttle(async () => {
// ModalCtrl.showModal(JumpConfirmPop, {
// confirmCb: () => {
// diffJump(this.props.realBuyJumpUrl);
// },
// });
});
clickSimulateSell = _throttle(async () => {
const { sellInput } = this.state;
console.log(sellInput);
if (!+sellInput || sellInput.toString().trim() === "") {
// Toast.show("请输入赎回份额");
return;
}
if (+(+sellInput * 100).toFixed(0) > this.state.tranche) {
// Toast.show("超出赎回上限啦");
}
// ModalCtrl.showModal(SellPanel, {
// name: this.state.productName,
// amount: sellInput,
// call: async () => {
// const { success } = await API.redeem({ code: this.props.code, amount: +(+sellInput * 100).toFixed(0) });
// this.updateInfo();
// if (!success) return;
// Toast.show("赎回成功");
// },
// });
});
// 新增:输入校验,只允许数字和最多两位小数
handleInputChange = (e, key) => {
const value = e.target.value;
// 只允许输入数字和最多两位小数
if (value === "" || /^\d*(\.\d{0,2})?$/.test(value)) {
this.setState({
[key]: value,
});
}
};
clickBack = () => {
modal.changePage(PAGE_MAP.ACTUAL_HOME_PAGE);
};
render() {
const {
tabType,
iframeUrl,
productName,
totalProfit,
tranche,
minBuyLimit,
marketValue,
yesterdayProfit,
availableFunds,
sellInput,
buyInput,
} = this.state;
const isBuy = tabType == EOpType.Buy;
const isBuyed = totalProfit || tranche || marketValue || yesterdayProfit;
// const isBuyed = false;
return (
<div className="DetailPage">
{isBuyed ? (
<div className="topArea">
<div className="productName">{productName}</div>
<div className="label1">累计收益(元)</div>
<div className="totalProfit">{totalProfit / 100}</div>
<div className="label2">持有份额</div>
<div className="tranche">{tranche / 100}</div>
<div className="label3">持有市值(元)</div>
<div className="marketValue">{marketValue / 100}</div>
<div className="label4">昨日收益(元)</div>
<div className="yesterdayProfit">{yesterdayProfit / 100}</div>
</div>
) : (
<div className="topArea2">
<div className="productName">{productName}</div>
</div>
)}
<iframe className="prodIframe" src={iframeUrl} />
<motion.div className="options">
<div className="tab">
<div
className="tabItem"
style={{
color: tabType == EOpType.Buy ? "#EA1211" : "#333333",
}}
onClick={() => this.clickTab(EOpType.Buy)}>
购买
</div>
<div
className="tabItem"
style={{
color: tabType == EOpType.Sell ? "#EA1211" : "#333333",
}}
onClick={() => this.clickTab(EOpType.Sell)}>
赎回
</div>
<motion.div className="actBar" animate={{ left: (isBuy ? 80 : 455) * remScale }} />
</div>
<motion.div
className="buy"
style={{
opacity: isBuy ? 1 : 0,
}}
transition={{ type: "tween" }}
initial={{ x: 0 }}
animate={{ x: isBuy ? 0 : 750 * remScale }}>
<div className="buyInfo">
<div>买入金额</div>
<span>可用资金:{availableFunds / 100}</span>
</div>
<input
className="bugInput"
placeholder={`¥最低买入${minBuyLimit / 100}元`}
type="text"
inputMode="decimal"
value={buyInput}
onChange={(e) => this.handleInputChange(e, "buyInput")}
/>
<div className="tip">
首次购买{minBuyLimit / 100}元起 再次购买{minBuyLimit / 100}元起 {minBuyLimit / 100}元递增
</div>
<div className="btnArea">
<Button className="btn simulate" onClick={this.clickSimulateBuy}>
模拟买入
</Button>
<Button className="btn really" onClick={this.clickReallyBuy}>
真实买入
</Button>
</div>
</motion.div>
<motion.div
className="sell"
transition={{ type: "tween" }}
initial={{ x: 750 * remScale }}
animate={{ x: isBuy ? 750 * remScale : 0 }}>
<div className="sellInfo">
<div>赎回份额</div>
<span>持有份额:{tranche / 100}</span>
</div>
<div className="sellInput">
<input
value={sellInput}
type="text"
inputMode="decimal"
placeholder={`最多可赎回${tranche / 100}份`}
onChange={(e) => this.handleInputChange(e, "sellInput")}
/>
<Button
className="sellAll"
onClick={() => {
this.setState({
sellInput: tranche / 100,
});
}}>
全部
</Button>
</div>
<div className="tip">{" "}</div>
<div className="btnArea">
<Button
className={classNames("btn", "simulate")}
style={{ width: "100%" }}
onClick={this.clickSimulateSell}>
模拟赎回
</Button>
</div>
</motion.div>
</motion.div>
<Button className={classNames("backBtn", isBuyed ? "backBtn2" : "")} onClick={this.clickBack} />
</div>
);
}
}
export default DetailPage;
import React, { useState } from "react";
import { Button } from "@src/components/Button";
import "./index.less";
// 转换为函数组件以正确使用Hooks
const ProductListModule = (props) => {
const [curTab, setCurTab] = useState(1);
const { curTabProductList = [], RATE_NAME = {} } = props;
// 切换标签页
const toggleTab = (tab) => {
setCurTab(tab);
};
// 处理金额格式化
const settleMoney = (money) => {
// 这里应该实现金额格式化逻辑
return money.toFixed(2);
};
// 跳转到详情页
const jumpVirtualDetailHandle = (item) => {
// 这里应该实现跳转逻辑
console.log("跳转到产品详情:", item);
};
return (
<div className="bottom_products">
{curTab === 1 && <span className="tab1_bg"></span>}
{curTab === 2 && <span className="tab2_bg"></span>}
<span className="tab1_btn" onClick={() => toggleTab(1)}></span>
<span className="tab2_btn" onClick={() => toggleTab(2)}></span>
<div className="products_list">
{curTabProductList.map((item, index) => (
<div className="b_product_item" key={`r_prdct_${index}`}>
<span className="b_product_name">{item.name}</span>
{curTab === 2 ? (
<>
<div className="b_product_rate">
<span className="b_product_rate_value">{settleMoney(item.totalProfit || 0)}</span>
<span className="b_product_rate_label">累计收益</span>
</div>
<div className="b_product_shu">
<span className="b_product_shu_value">{settleMoney(item.positionMoney || 0)}</span>
<span className="b_product_shu_label">持仓金额</span>
</div>
</>
) : (
<>
<div className="b_product_rate">
{item.rate !== undefined && item.rate !== null && (
<span className="b_product_rate_value">{(item.rate / 100).toFixed(2)}%</span>
)}
<span className="b_product_rate_label">{RATE_NAME[item.type] || "年化收益率"}</span>
</div>
<div className="b_product_shu">
<span className="b_product_shu_value">{item.shenShuGuiZei}</span>
<span className="b_product_shu_label">
{item.fengXian}{item.qigouText}
</span>
</div>
</>
)}
<Button className="detail_btn_1" onClick={() => jumpVirtualDetailHandle(item)}></Button>
<span className="b_product_line"></span>
</div>
))}
</div>
{!curTabProductList.length && curTab === 2 && <div className="empty">暂无持仓产品哦</div>}
</div>
);
};
export default ProductListModule;
@import "../../../res.less";
.bottom_products {
width: 700px;
height: auto;
min-height: 1017px;
background-color: #ffffff;
position: relative;
padding-top: 152px;
padding-bottom: 19px;
box-sizing: border-box;
border-radius: 24px;
margin-left: 24px;
// &::before {
// content: "";
// position: absolute;
// top: 800px;
// left: 15px;
// width: 685px;
// height: calc(100% - 800px - 19px);
// background-color: #fff;
// border-radius: 0 0 20px 20px;
// }
.tab1_bg {
width: 701px;
height: 1017px;
left: 0;
top: 0px;
position: absolute;
.sparkBg("ActualHome/tab1_bg.png");
}
.tab2_bg {
width: 701px;
height: 1017px;
left: 0;
top: 0px;
position: absolute;
.sparkBg("ActualHome/tab2_bg.png");
}
.tab1_btn {
width: 50%;
height: 80px;
position: absolute;
left: 0;
top: 0;
}
.tab2_btn {
width: 50%;
height: 80px;
position: absolute;
right: 0;
top: 0;
// background-color: rgba(0, 0, 0, 0.6);
}
.empty {
width: 653px;
left: 30px;
top: 252px;
position: absolute;
color: #000;
text-align: center;
}
.products_list {
width: 653px;
// height: 696px;
left: 30px;
// top: 152px;
position: relative;
.b_product_item {
width: 653px;
height: 173px;
position: relative;
&:not(:last-child) {
margin-bottom: 50px;
}
.b_product_name {
width: 650px;
height: 30px;
left: 0px;
top: 0px;
position: absolute;
font-size: 28px;
line-height: 30px;
color: rgba(1, 1, 1, 1);
font-weight: bold;
}
.b_product_rate {
width: 200px;
height: 63px;
left: 0px;
top: 57px;
position: absolute;
.b_product_rate_label {
width: 100%;
height: 22px;
left: 0px;
top: 46px;
position: absolute;
opacity: 0.6;
font-size: 20px;
line-height: 22px;
color: rgba(1, 1, 1, 1);
.lineClamp1();
}
.b_product_rate_value {
width: 100%;
height: 32px;
left: 2px;
top: 0px;
position: absolute;
font-size: 32px;
line-height: 32px;
color: rgba(211, 26, 25, 1);
font-weight: bold;
.lineClamp1();
}
}
.b_product_shu {
width: 280px;
height: 63px;
left: 222px;
top: 57px;
position: absolute;
.b_product_shu_label {
width: 100%;
height: 22px;
left: 1px;
top: 45px;
position: absolute;
opacity: 0.6;
font-size: 20px;
line-height: 22px;
color: rgba(1, 1, 1, 1);
.lineClamp1();
}
.b_product_shu_value {
width: 100%;
height: 32px;
left: 0px;
top: -2px;
position: absolute;
font-size: 28px;
line-height: 32px;
color: rgba(0, 0, 0, 1);
font-weight: bold;
.lineClamp1();
}
}
.detail_btn_1 {
width: 140px;
height: 49px;
left: 513px;
top: 65px;
position: absolute;
.sparkBg("ActualHome/detail_btn.png");
}
.b_product_line {
width: 652px;
height: 2px;
left: 1px;
top: 171px;
position: absolute;
opacity: 0.1;
.sparkBg("ActualHome/b_product_line.png");
}
}
}
}
......@@ -8,7 +8,7 @@
width: 732px;
height: 407px;
.webpBg("ActualHome/sign_bg.png");
margin: 0 auto;
margin: 0 auto 10px;
}
.week-list-box {
......@@ -25,7 +25,7 @@
position: relative;
width: 82px;
height: 107px;
.webpBg("ActualHome/sign_task.png")
.webpBg("ActualHome/sign_task.png");
}
.week-item-text {
......@@ -46,7 +46,7 @@
position: absolute;
top: -26px;
left: -1px;
.webpBg("ActualHome/sign_task_title.png")
.webpBg("ActualHome/sign_task_title.png");
}
}
......@@ -56,5 +56,5 @@
position: absolute;
left: 149px;
top: 280px;
.webpBg("ActualHome/sign_btn.png")
.webpBg("ActualHome/sign_btn.png");
}
......@@ -17,7 +17,7 @@ const store = makeAutoObservable({
myPrize: "myPrize",
// TODO 举例子 新宿台奖品页
index: PAGE_MAP.ACTUAL_HOME_PAGE,
}[skinId] || PAGE_MAP.PRIZE_PAGE,
}[skinId] || PAGE_MAP.ACTUAL_HOME_PAGE,
pageData: {},
/** 场景切换 */
changePage(page, data = {}) {
......
......@@ -20,4 +20,6 @@ export const PAGE_MAP = {
LOADING_PAGE: "loadingPage",
/** 奖品页 */
PRIZE_PAGE: "prizePage",
/** 产品详情 */
PRODUCT_DETAIL: "productDetail",
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment