<s:iterator> 用index 显示多列

本文介绍了一个使用Struts框架实现的新闻查询应用实例。该应用通过Struts框架处理新闻查询请求,并展示分页显示的新闻列表。每页显示18条新闻记录,分为三组进行布局。文章还涉及了Struts标签库的应用以及简单的JavaServer Pages (JSP) 语法。
<div class="line1">
<ul>
<%
int countcy = 1;
%>
<s:iterator value="#loadNews.paginationSupport.items" status="st">
<%
if(countcy <= 6){
%>
<li><a href="/queryNews.action?id=<s:property value="id"/>" target="_blank"><div limit="17"><s:property value="titles" escape="false" /></div></a></li>
<%
}
countcy++;
%>
</s:iterator>
</ul>
</div>

<div class="line"></div>


<div class="line1">
<ul>
<%
int countcy2 = 1;
%>
<s:iterator value="#loadNews.paginationSupport.items" status="st">
<%
if(countcy2 <= 6){
%>
<li><a href="/queryNews.action?id=<s:property value="#loadNews.paginationSupport.items[#st.index+6].id"/>" target="_blank"><div limit="17"><s:property value="#loadNews.paginationSupport.items[#st.index+6].titles" escape="false" /></div></a></li>
<%
}
countcy2++;
%>

</s:iterator>
</ul>
</div>
<div class="line"></div>
<div class="line1">
<ul>
<%
int countcy3 = 1;
%>
<s:iterator value="#loadNews.paginationSupport.items" status="st">
<%
if(countcy3 <= 6){
%>
<li><a href="/queryNews.action?id=<s:property value="#loadNews.paginationSupport.items[#st.index+12].id"/>" target="_blank"><div limit="17"><s:property value="#loadNews.paginationSupport.items[#st.index+12].titles" escape="false" /></div></a></li>
<%
}
countcy3++;
%>
</s:iterator>
</ul>
</div>
// 价格表管理类 class PriceTableManager { public: static PriceTableManager* GetInstance(); void LoadPriceTable(PriceTableType type, const std::string& filePath, const std::string& sheetName); double GetPrice(PriceTableType type, const std::string& name, const std::string& model, const std::string& brand); double GetAveragePrice(PriceTableType type, const std::string& name, const std::string& model); double CalculateAveragePrice(PriceTableType type, const std::string& name, const std::string& model); private: PriceTableManager(); static PriceTableManager* instance; std::vector<MaterialInfo> steelPriceTable; std::vector<MaterialInfo> standardPriceTable; std::map<std::string, std::map<std::string, std::map<std::string, MaterialInfo>>> steelIndex; std::map<std::string, std::map<std::string, std::map<std::string, MaterialInfo>>> standardIndex; bool steelPriceTableLoaded; bool standardPriceTableLoaded; void BuildIndex(PriceTableType type); void ReadFromExcel(PriceTableType type, XlsBook* xlsBook, const std::string& sheetName); std::string& trim(std::string& s); }; PriceTableManager* PriceTableManager::instance = NULL; PriceTableManager* PriceTableManager::GetInstance() { if (instance == NULL) { instance = new PriceTableManager(); } return instance; } PriceTableManager::PriceTableManager() { steelPriceTableLoaded = false; standardPriceTableLoaded = false; } void PriceTableManager::LoadPriceTable(PriceTableType type, const std::string& filePath, const std::string& sheetName) { if ((type == PRICE_TABLE_STEEL && steelPriceTableLoaded) || (type == PRICE_TABLE_STANDARD && standardPriceTableLoaded)) { return; } printf_str(filePath); XlsBook* xlsBook = new XlsBook(filePath); printf_str("filePath"); ReadFromExcel(type, xlsBook, sheetName); printf_str("filePath"); BuildIndex(type); delete xlsBook; if (type == PRICE_TABLE_STEEL) { steelPriceTableLoaded = true; } else { standardPriceTableLoaded = true; } } void PriceTableManager::ReadFromExcel(PriceTableType type, XlsBook* xlsBook, const std::string& sheetName) { BookSheet* workSheet = xlsBook->getSheet(sheetName.c_str()); std::vector<std::string> brandCol = workSheet->getSheetCol(0); std::vector<std::string> modelCol = workSheet->getSheetCol(1); std::vector<std::string> priceCol = workSheet->getSheetCol(2); std::vector<std::string> nameCol = workSheet->getSheetCol(3); // 不再读取均价列 std::vector<MaterialInfo>* priceTable = (type == PRICE_TABLE_STEEL) ? &steelPriceTable : &standardPriceTable; priceTable->clear(); for (size_t i = 1; i < nameCol.size(); i++) { if (i >= modelCol.size() || i >= brandCol.size() || i >= priceCol.size()) { break; } MaterialInfo info; info.name = trim(nameCol[i]); info.model = trim(modelCol[i]); info.brand = trim(brandCol[i]); info.price = atof(priceCol[i].c_str()); info.avgPrice = 0.0; if (i>100) { break; } priceTable->push_back(info); } } double PriceTableManager::CalculateAveragePrice(PriceTableType type, const std::string& name, const std::string& model) { std::vector& priceTable = (type == PRICE_TABLE_STEEL) ? steelPriceTable : standardPriceTable; double totalPrice = 0.0; int count = 0; // 遍历价格表,计算同名称同型号的平均价格 for (size_t i = 0; i < priceTable.size(); i++) { const MaterialInfo& info = priceTable[i]; if (info.name == name && info.model == model) { totalPrice += info.price; count++; } } if (count > 0) { return totalPrice / count; } return 0.0; } void PriceTableManager::BuildIndex(PriceTableType type) { std::vector& priceTable = (type == PRICE_TABLE_STEEL) ? steelPriceTable : standardPriceTable; std::map<std::string, std::map<std::string, std::map<std::string, MaterialInfo>>>& index =(type == PRICE_TABLE_STEEL) ? steelIndex : standardIndex; index.clear(); for (size_t i = 0; i < priceTable.size(); i++) { const MaterialInfo& info = priceTable[i]; index[info.name][info.model][info.brand] = info; } for (size_t i = 0; i < priceTable.size(); i++) { MaterialInfo& info = priceTable[i]; info.avgPrice = CalculateAveragePrice(type, info.name, info.model); index[info.name][info.model][info.brand].avgPrice = info.avgPrice; } } double PriceTableManager::GetPrice(PriceTableType type, const std::string& name, const std::string& model, const std::string& brand) { std::map<std::string, std::map<std::string, std::map<std::string, MaterialInfo>>>& index = (type == PRICE_TABLE_STEEL) ? steelIndex : standardIndex; std::string n = name; std::string m = model; std::string b = brand; trim(n); trim(m); trim(b); if (index.find(n) != index.end() && index[n].find(m) != index[n].end() && index[n][m].find(b) != index[n][m].end()) { return index[n][m][b].price; } if (index.find(n) != index.end() && index[n].find(m) != index[n].end() && !index[n][m].empty()) { return index[n][m].begin()->second.price; } return 0.0; } double PriceTableManager::GetAveragePrice(PriceTableType type, const string& name, const string& model) { map<string, map<string,map<string, MaterialInfo>>>& index =(type == PRICE_TABLE_STEEL) ? steelIndex : standardIndex; string n = name; string m = model; trim(n); trim(m); if (index.find(n) != index.end() && index[n].find(m) != index[n].end()) { const map<string, MaterialInfo>& brands = index[n][m]; if (brands.empty()) return 0.0; double total = 0.0; int count = 0; for (map<string, MaterialInfo>::const_iterator it = brands.begin(); it != brands.end(); ++it) { total += it->second.price; count++; } return total / count; } return 0.0; } std::string& PriceTableManager::trim(std::string& s) { s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace)))); s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end()); return s; } 首先数据输入没问题的情况下代码在进行价格查询的时候查询不到现有的价格,请详细读代码并改正
09-13
#include "pch.h" #include "TCalcFuncSets.h" #include <windows.h> #include <string> #include <vector> #include <fstream> #include <sstream> #include <map> #include <algorithm> #include <iostream> #include <cmath> #include <cctype> #include <unordered_map> #include <mutex> #include <memory> // 用于std::make_shared #include <chrono> // 用于std::chrono时间功能 // 缓存项结构体 struct CacheEntry { std::map<std::string, float> data; std::chrono::steady_clock::time_point lastAccessed; CacheEntry() : lastAccessed(std::chrono::steady_clock::now()) {} }; // 统一的缓存管理类 class QuantileCache { private: std::unordered_map<std::string, CacheEntry> cache_; std::mutex mutex_; const size_t maxCacheSize_ = 100; // 最大缓存项数量 public: // 尝试从缓存获取数据 bool tryGet(const std::string& key, std::map<std::string, float>& result) { std::lock_guard<std::mutex> lock(mutex_); auto it = cache_.find(key); if (it != cache_.end()) { // 更新访问时间 it->second.lastAccessed = std::chrono::steady_clock::now(); result = it->second.data; return true; } return false; } // 存储数据到缓存 void put(const std::string& key, const std::map<std::string, float>& data) { std::lock_guard<std::mutex> lock(mutex_); // 清理过期缓存项 if (cache_.size() >= maxCacheSize_) { evictOldEntries(); } cache_[key].data = data; cache_[key].lastAccessed = std::chrono::steady_clock::now(); } private: // 移除最旧的缓存项 void evictOldEntries() { // 找到最旧的缓存项 auto oldestIt = cache_.begin(); for (auto it = cache_.begin(); it != cache_.end(); ++it) { if (it->second.lastAccessed < oldestIt->second.lastAccessed) { oldestIt = it; } } // 移除最旧的缓存项 cache_.erase(oldestIt); } }; // 全局缓存实例 static QuantileCache g_quantileCache; // 清理字符串中的空白字符 std::string CleanString(const std::string& str) { std::string result; result.reserve(str.size()); for (unsigned int i = 0; i < str.size(); i++) { char c = str[i]; if (!std::isspace((unsigned char)c)) { result.push_back(c); } } return result; } // 清理路径中的无效字符 std::string CleanPath(const std::string& path) { std::string result; result.reserve(path.size()); for (unsigned int i = 0; i < path.size(); i++) { char c = path[i]; if (c == ' ' || !std::isspace((unsigned char)c)) { result.push_back(c); } } return result; } // 将通达信日期格式转换为标准日期格式(yyyymmdd) std::string ConvertTDXDateToYYYYMMDD(float tdxDate) { int dateInt = (int)tdxDate + 19000000; if (dateInt <= 19000000 || dateInt > 21000000) { return ""; } char buffer[16]; sprintf_s(buffer, sizeof(buffer), "%d", dateInt); return std::string(buffer); } // 快速解析日期字符串 std::string ParseDateString(const std::string& dateStr) { // 移除引号 std::string cleaned = dateStr; if (!cleaned.empty() && cleaned[0] == '"') { cleaned = cleaned.substr(1); } if (!cleaned.empty() && cleaned[cleaned.length() - 1] == '"') { cleaned = cleaned.substr(0, cleaned.length() - 1); } // 如果已经是yyyymmdd格式 if (cleaned.length() == 8 && cleaned.find_first_not_of("0123456789") == std::string::npos) { return cleaned; } // 处理分隔符格式 int year = 0, month = 0, day = 0; size_t firstDelim = cleaned.find_first_of("-/\/"); if (firstDelim != std::string::npos) { size_t secondDelim = cleaned.find_first_of("-/\/", firstDelim + 1); if (secondDelim != std::string::npos) { year = atoi(cleaned.substr(0, firstDelim).c_str()); month = atoi(cleaned.substr(firstDelim + 1, secondDelim - firstDelim - 1).c_str()); day = atoi(cleaned.substr(secondDelim + 1).c_str()); } } else if (cleaned.length() == 8) { year = atoi(cleaned.substr(0, 4).c_str()); month = atoi(cleaned.substr(4, 2).c_str()); day = atoi(cleaned.substr(6, 2).c_str()); } if (year > 1900 && year < 2100 && month >= 1 && month <= 12 && day >= 1 && day <= 31) { char buffer[16]; sprintf_s(buffer, sizeof(buffer), "%04d%02d%02d", year, month, day); return std::string(buffer); } return ""; } // 处理单个CSV文件并提取指定列的数据 bool ProcessSingleCSVFileForColumn(const std::string& filePath, std::map<std::string, std::vector<double> >& dateColumnMap, int columnIdx) { std::ifstream inFile(filePath.c_str()); if (!inFile.is_open()) { return false; } // 跳过表头 std::string headerLine; if (!std::getline(inFile, headerLine)) { inFile.close(); return false; } std::string line; while (std::getline(inFile, line)) { std::istringstream lineIss(line); std::string token; int columnIndex = 0; std::string dateStr; double columnValue = 0.0; bool hasValue = false; while (std::getline(lineIss, token, ',')) { std::string cleanedToken = CleanString(token); if (columnIndex == 0) { // date列 dateStr = ParseDateString(cleanedToken); } else if (columnIndex == columnIdx) { // 指定列 if (!cleanedToken.empty()) { columnValue = atof(cleanedToken.c_str()); hasValue = true; } } columnIndex++; } // 只有当日期有效且指定列有值时才添加 if (!dateStr.empty() && hasValue) { dateColumnMap[dateStr].push_back(columnValue); } } inFile.close(); return true; } // 处理单个CSV文件并计算N日涨跌幅 bool ProcessSingleCSVFileForReturns(const std::string& filePath, std::map<std::string, std::vector<double> >& dateReturnsMap, int N) { std::ifstream inFile(filePath.c_str()); if (!inFile.is_open()) { return false; } // 跳过表头 std::string headerLine; if (!std::getline(inFile, headerLine)) { inFile.close(); return false; } // 预分配向量空间以提高性能 std::vector<std::string> dates; std::vector<double> closePrices; dates.reserve(1000); // 预估每只股票约1000个交易日 closePrices.reserve(1000); std::string line; while (std::getline(inFile, line)) { std::istringstream lineIss(line); std::string token; int columnIndex = 0; std::string dateStr; double closePrice = 0.0; while (std::getline(lineIss, token, ',')) { std::string cleanedToken = CleanString(token); if (columnIndex == 0) { // date列 dateStr = ParseDateString(cleanedToken); } else if (columnIndex == 5) { // close列 if (!cleanedToken.empty()) { closePrice = atof(cleanedToken.c_str()); } } columnIndex++; } dates.push_back(dateStr); closePrices.push_back(closePrice); } inFile.close(); // 计算N日涨跌幅 for (unsigned int i = N; i < closePrices.size(); i++) { if (!dates[i].empty() && closePrices[i] > 0 && closePrices[i - N] > 0) { double returnRate = (closePrices[i] - closePrices[i - N]) / closePrices[i - N] * 100.0; dateReturnsMap[dates[i]].push_back(returnRate); } } return true; } // 优化的文件处理函数 - 用于计算指定列的分位数 void ReadCSVAndCalculateColumnData(const std::string& directory, std::map<std::string, std::vector<double> >& dateColumnMap, int columnIdx) { WIN32_FIND_DATAA findData; std::string cleanedDirectory = CleanPath(directory); std::string searchPath = cleanedDirectory + "\\*.csv"; HANDLE hFind = FindFirstFileA(searchPath.c_str(), &findData); if (hFind == INVALID_HANDLE_VALUE) { return; } do { if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { std::string fileName(findData.cFileName); std::string filePath = cleanedDirectory + "\\" + fileName; filePath = CleanPath(filePath); ProcessSingleCSVFileForColumn(filePath, dateColumnMap, columnIdx); } } while (FindNextFileA(hFind, &findData) != 0); FindClose(hFind); } // 优化的文件处理函数 - 用于计算N日涨跌幅 void ReadCSVAndCalculateReturns(const std::string& directory, std::map<std::string, std::vector<double> >& dateReturnsMap, int N) { WIN32_FIND_DATAA findData; std::string cleanedDirectory = CleanPath(directory); std::string searchPath = cleanedDirectory + "\\*.csv"; HANDLE hFind = FindFirstFileA(searchPath.c_str(), &findData); if (hFind == INVALID_HANDLE_VALUE) { return; } do { if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { std::string fileName(findData.cFileName); std::string filePath = cleanedDirectory + "\\" + fileName; filePath = CleanPath(filePath); ProcessSingleCSVFileForReturns(filePath, dateReturnsMap, N); } } while (FindNextFileA(hFind, &findData) != 0); FindClose(hFind); } // 函数前向声明 template <typename DataReaderFunc> void ProcessQuantileData( const std::string& csvDirectory, std::map<std::string, float>& dateQuantileMap, DataReaderFunc readDataFunc, float quantile ); template <typename DataReaderFunc> void ProcessQuantileData( const std::string& csvDirectory, std::map<std::string, float>& dateQuantileMap, DataReaderFunc readDataFunc, float quantile, std::map<std::string, std::vector<double>>& dateDataMap ); float CalculateQuantile(const std::vector<double>& data, float quantile); // 通用分位数数据处理函数 // 提取两个主要函数的公共数据处理逻辑 template <typename DataReaderFunc> void ProcessQuantileData( const std::string& csvDirectory, std::map<std::string, float>& dateQuantileMap, DataReaderFunc readDataFunc, float quantile ) { // 存储日期对应的数据 std::map<std::string, std::vector<double>> dateDataMap; // 调用传入的函数读取数据 readDataFunc(csvDirectory, dateDataMap); // 计算每个日期的分位数 for (const auto& entry : dateDataMap) { dateQuantileMap[entry.first] = CalculateQuantile(entry.second, quantile); } // 清理数据以释放内存 dateDataMap.clear(); } // 兼容不同参数类型的重载版本 template <typename DataReaderFunc> void ProcessQuantileData( const std::string& csvDirectory, std::map<std::string, float>& dateQuantileMap, DataReaderFunc readDataFunc, float quantile, std::map<std::string, std::vector<double>>& dateDataMap ) { // 调用传入的函数读取数据 readDataFunc(csvDirectory, dateDataMap); // 计算每个日期的分位数 for (const auto& entry : dateDataMap) { dateQuantileMap[entry.first] = CalculateQuantile(entry.second, quantile); } } // 计算分位数 - 使用O(n)时间复杂度的优化算法 float CalculateQuantile(const std::vector<double>& data, float quantile) { if (data.empty()) { return 0.0f; } if (quantile < 0.0f) quantile = 0.0f; if (quantile > 1.0f) quantile = 1.0f; std::vector<double> sortedData = data; size_t n = sortedData.size(); double pos = quantile * (n - 1); int lowerIndex = static_cast<int>(pos); int upperIndex = lowerIndex + 1; // 对于精确索引的情况,直接使用nth_element if (lowerIndex == upperIndex || upperIndex >= static_cast<int>(n)) { std::nth_element(sortedData.begin(), sortedData.begin() + lowerIndex, sortedData.end()); return static_cast<float>(sortedData[lowerIndex]); } // 对于需要插值的情况,找到两个位置的元素 // 先找lowerIndex位置的元素 std::nth_element(sortedData.begin(), sortedData.begin() + lowerIndex, sortedData.end()); double lowerValue = sortedData[lowerIndex]; // 再在lowerIndex之后的范围内找upperIndex位置的元素 std::nth_element(sortedData.begin() + lowerIndex + 1, sortedData.begin() + upperIndex, sortedData.end()); double upperValue = sortedData[upperIndex]; // 线性插值计算最终分位数值 double fractionalPart = pos - lowerIndex; double quantileValue = lowerValue + fractionalPart * (upperValue - lowerValue); return static_cast<float>(quantileValue); } // 生成缓存键值 std::string GenerateColumnCacheKey(int columnIdx, float quantile) { char buffer[64]; sprintf_s(buffer, "column_%d_%.2f", columnIdx, quantile); return std::string(buffer); } std::string GenerateReturnsCacheKey(int N, float quantile) { char buffer[64]; sprintf_s(buffer, "returns_%d_%.2f", N, quantile); return std::string(buffer); } // 函数2 - 计算指定列的分位数 void CalculateColumnQuantileReturns(int DataLen, float* pfOUT, float* pfINa, float* pfINb, float* pfINc) { // 初始化输出数组为0 for (int i = 0; i < DataLen; i++) { pfOUT[i] = 0.0f; } // 获取列索引和分位数参数 int columnIdx = (int)(pfINb[0] + 0.5f); // M参数表示列号 float quantile = pfINc[0]; // N参数表示分位数 // 生成缓存键值,添加前缀以区分不同类型的缓存 std::string cacheKey = "column:" + GenerateColumnCacheKey(columnIdx, quantile); // 检查缓存中是否已有计算结果 std::map<std::string, float> dateQuantileMap; bool hasCache = g_quantileCache.tryGet(cacheKey, dateQuantileMap); // 如果缓存中没有,则进行计算 if (!hasCache) { // 设置CSV文件的目录 const std::string csvDirectory = "F:\\His_STOCKDATA"; // 使用堆分配存储日期对应的指定列数据,避免栈溢出 auto dateColumnMap = std::make_shared<std::map<std::string, std::vector<double>>>(); // 读取CSV文件并提取指定列的数据 ReadCSVAndCalculateColumnData(csvDirectory, *dateColumnMap, columnIdx); // 计算每个日期的分位数 for (const auto& entry : *dateColumnMap) { dateQuantileMap[entry.first] = CalculateQuantile(entry.second, quantile); } // 自动释放内存(通过shared_ptr的作用域) // 将结果存入缓存 g_quantileCache.put(cacheKey, dateQuantileMap); } // 将结果匹配到输出数组 for (int i = 0; i < DataLen; i++) { std::string dateStr = ConvertTDXDateToYYYYMMDD(pfINa[i]); if (dateStr.empty() || dateStr.length() != 8) { pfOUT[i] = 0.0f; continue; } std::map<std::string, float>::const_iterator iter = dateQuantileMap.find(dateStr); if (iter != dateQuantileMap.end()) { pfOUT[i] = iter->second; } else { pfOUT[i] = 0.0f; } } } // 函数3 - 快速计算分位数收益 void CalculateQuantileReturns(int DataLen, float* pfOUT, float* pfINa, float* pfINb, float* pfINc) { // 初始化输出数组为0 for (int i = 0; i < DataLen; i++) { pfOUT[i] = 0.0f; } // 获取N和M的值 int N = (int)(pfINb[0] + 0.5f); float M = pfINc[0]; // 生成缓存键值,添加前缀以区分不同类型的缓存 std::string cacheKey = "returns:" + GenerateReturnsCacheKey(N, M); // 检查缓存中是否已有计算结果 std::map<std::string, float> dateQuantileMap; bool hasCache = g_quantileCache.tryGet(cacheKey, dateQuantileMap); // 如果缓存中没有,则进行计算 if (!hasCache) { // 设置CSV文件的目录 const std::string csvDirectory = "F:\\His_STOCKDATA"; // 使用堆分配存储日期对应的涨跌幅数据,避免栈溢出 auto dateReturnsMap = std::make_shared<std::map<std::string, std::vector<double>>>(); // 读取CSV文件并计算N日涨跌幅 ReadCSVAndCalculateReturns(csvDirectory, *dateReturnsMap, N); // 计算每个日期的分位数 for (const auto& entry : *dateReturnsMap) { dateQuantileMap[entry.first] = CalculateQuantile(entry.second, M); } // 自动释放内存(通过shared_ptr的作用域) // 将结果存入缓存 g_quantileCache.put(cacheKey, dateQuantileMap); } // 将结果匹配到输出数组 for (int i = 0; i < DataLen; i++) { std::string dateStr = ConvertTDXDateToYYYYMMDD(pfINa[i]); if (dateStr.empty() || dateStr.length() != 8) { pfOUT[i] = 0.0f; continue; } std::map<std::string, float>::const_iterator iter = dateQuantileMap.find(dateStr); if (iter != dateQuantileMap.end()) { pfOUT[i] = iter->second; } else { pfOUT[i] = 0.0f; } } } // 函数注册 PluginTCalcFuncInfo g_CalcFuncSets[] = { {2, (pPluginFUNC)CalculateColumnQuantileReturns}, {3, (pPluginFUNC)CalculateQuantileReturns}, {0, NULL}, }; BOOL RegisterTdxFunc(PluginTCalcFuncInfo** pFun) { if (*pFun == NULL) { (*pFun) = g_CalcFuncSets; return TRUE; } return FALSE; }有哪些值得优化的地方
最新发布
09-22
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值