daxiapi-cli 2.2.0 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +56 -0
- package/bin/index.js +3 -0
- package/commands/config.js +7 -17
- package/commands/dividend.js +3 -1
- package/commands/hotrank.js +63 -0
- package/commands/market.js +5 -3
- package/commands/report.js +32 -0
- package/commands/sector.js +5 -1
- package/commands/stock.js +4 -2
- package/commands/turnover.js +18 -0
- package/lib/api.js +178 -187
- package/lib/caibao.js +69 -0
- package/lib/dividendUtils.js +216 -0
- package/lib/iconv.js +4 -0
- package/lib/output.js +4 -2
- package/lib/request.js +44 -0
- package/lib/thsUtils.js +148 -0
- package/lib/utils.js +58 -2
- package/package.json +39 -35
package/lib/api.js
CHANGED
|
@@ -1,24 +1,12 @@
|
|
|
1
1
|
const axios = require('axios');
|
|
2
2
|
const config = require('./config');
|
|
3
|
+
const request = require('./request');
|
|
4
|
+
const {formatThsVolumeTime, isTradingNow} = require('./utils');
|
|
5
|
+
const {calculateScores} = require('./dividendUtils');
|
|
6
|
+
const getFinanceReportDetail = require('./caibao');
|
|
3
7
|
|
|
4
8
|
const BASE_URL = config.get('baseUrl') || 'https://daxiapi.com';
|
|
5
9
|
|
|
6
|
-
const DIVIDEND_SCORE_CONSTANTS = {
|
|
7
|
-
ROLLING_WINDOW: 440,
|
|
8
|
-
PERCENTILE_LOW: 5,
|
|
9
|
-
PERCENTILE_HIGH: 95,
|
|
10
|
-
SCORE_MA_PERIOD: 5,
|
|
11
|
-
EMA_PERIOD: 20,
|
|
12
|
-
MA_PERIOD: 80,
|
|
13
|
-
RSI_PERIOD: 20,
|
|
14
|
-
MIN_VALID_VALUES: 10,
|
|
15
|
-
MIN_SCORE: 0,
|
|
16
|
-
MAX_SCORE: 100,
|
|
17
|
-
CS_WEIGHT: 0.35,
|
|
18
|
-
MA80_WEIGHT: 0.35,
|
|
19
|
-
RSI_WEIGHT: 0.3
|
|
20
|
-
};
|
|
21
|
-
|
|
22
10
|
function createClient(token) {
|
|
23
11
|
return axios.create({
|
|
24
12
|
baseURL: `${BASE_URL}/coze`,
|
|
@@ -139,15 +127,17 @@ async function getDividendScore(token, code) {
|
|
|
139
127
|
}
|
|
140
128
|
|
|
141
129
|
let rawData = await axios.get(`${BASE_URL}/sk/${code}.json`);
|
|
142
|
-
if(!rawData.data){
|
|
130
|
+
if (!rawData.data) {
|
|
143
131
|
throw new Error('Failed to get kline data');
|
|
144
132
|
}
|
|
145
133
|
const klineData = rawData.data;
|
|
146
134
|
const klines = klineData.k || '';
|
|
147
|
-
const scores = calculateScores(
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
135
|
+
const scores = calculateScores(
|
|
136
|
+
klines.split(';').map(a => {
|
|
137
|
+
const [date, open, close, high, low, volume] = a.split(',');
|
|
138
|
+
return {date, close: Number(close), open: Number(open), high, low, vol: Number(volume)};
|
|
139
|
+
})
|
|
140
|
+
);
|
|
151
141
|
const recentScores = scores.slice(-60);
|
|
152
142
|
|
|
153
143
|
return {
|
|
@@ -162,195 +152,191 @@ async function getDividendScore(token, code) {
|
|
|
162
152
|
};
|
|
163
153
|
}
|
|
164
154
|
|
|
165
|
-
function
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
let ema = closes[0];
|
|
169
|
-
const multiplier = 2 / (period + 1);
|
|
170
|
-
|
|
171
|
-
for (let i = 0; i < closes.length; i++) {
|
|
172
|
-
if (i === 0) {
|
|
173
|
-
ema = closes[i];
|
|
174
|
-
} else {
|
|
175
|
-
ema = (closes[i] - ema) * multiplier + ema;
|
|
176
|
-
}
|
|
177
|
-
cs.push(((closes[i] - ema) / ema) * 100);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
return {cs};
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
function calculateMA(period, data) {
|
|
184
|
-
const closes = data.map(d => d.close);
|
|
185
|
-
const ma = [];
|
|
186
|
-
const maBias = [];
|
|
155
|
+
async function getStockRank(type = 'hour', listType = 'normal') {
|
|
156
|
+
try {
|
|
157
|
+
const params = {stock_type: 'a', list_type: listType};
|
|
187
158
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
159
|
+
// 只有 normal 和 skyrocket 才有 type 参数,默认为 hour
|
|
160
|
+
// 其他榜单类型固定为 day
|
|
161
|
+
if (listType === 'normal' || listType === 'skyrocket') {
|
|
162
|
+
params.type = type;
|
|
192
163
|
} else {
|
|
193
|
-
|
|
194
|
-
for (let j = 0; j < period; j++) {
|
|
195
|
-
sum += closes[i - j];
|
|
196
|
-
}
|
|
197
|
-
const avg = sum / period;
|
|
198
|
-
ma.push(avg);
|
|
199
|
-
maBias.push(((closes[i] - avg) / avg) * 100);
|
|
164
|
+
params.type = 'day';
|
|
200
165
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
sumLoss += Math.abs(c);
|
|
227
|
-
}
|
|
166
|
+
const response = await request.get('/fuyao/hot_list_data/out/hot_list/v1/stock', params);
|
|
167
|
+
const data = extractData(response, 'stock_list');
|
|
168
|
+
|
|
169
|
+
return data.map(a => {
|
|
170
|
+
const result = {
|
|
171
|
+
code: a.code,
|
|
172
|
+
name: a.name,
|
|
173
|
+
涨跌幅: a.rise_and_fall,
|
|
174
|
+
讨论热度: a.rate,
|
|
175
|
+
热榜变化: a.hot_rank_chg,
|
|
176
|
+
排名: a.display_order != null ? a.display_order : a.order != null ? a.order : 0
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
if (listType === 'normal' || listType === 'skyrocket') {
|
|
180
|
+
result.上涨原因 = a.analyse_title;
|
|
181
|
+
result.上涨分析 = a.analyse
|
|
182
|
+
?.split('\n')
|
|
183
|
+
.map(line => {
|
|
184
|
+
if (line.includes('免责声明')) {
|
|
185
|
+
return '';
|
|
186
|
+
}
|
|
187
|
+
return line.trim();
|
|
188
|
+
})
|
|
189
|
+
.filter(line => line !== '')
|
|
190
|
+
.join('\n');
|
|
228
191
|
}
|
|
229
|
-
gains = sumGain / period;
|
|
230
|
-
losses = sumLoss / period;
|
|
231
|
-
} else {
|
|
232
|
-
const currentGain = change > 0 ? change : 0;
|
|
233
|
-
const currentLoss = change < 0 ? Math.abs(change) : 0;
|
|
234
|
-
gains = (gains * (period - 1) + currentGain) / period;
|
|
235
|
-
losses = (losses * (period - 1) + currentLoss) / period;
|
|
236
|
-
}
|
|
237
192
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
}
|
|
193
|
+
return result;
|
|
194
|
+
});
|
|
195
|
+
} catch (err) {
|
|
196
|
+
console.error('[getStockRank] 获取热股榜数据失败:', err);
|
|
197
|
+
throw err;
|
|
244
198
|
}
|
|
245
|
-
|
|
246
|
-
return rsiValues;
|
|
247
199
|
}
|
|
248
200
|
|
|
249
|
-
function
|
|
250
|
-
|
|
251
|
-
|
|
201
|
+
async function getPlateRank(type = 'concept') {
|
|
202
|
+
try {
|
|
203
|
+
const response = await request.get('/fuyao/hot_list_data/out/hot_list/v1/plate', {type});
|
|
204
|
+
const data = extractData(response, 'plate_list');
|
|
205
|
+
|
|
206
|
+
return data.map(d => {
|
|
207
|
+
// - code: "881160"
|
|
208
|
+
// rise_and_fall: 1.4869
|
|
209
|
+
// etf_rise_and_fall: -0.1488
|
|
210
|
+
// hot_rank_chg: 0
|
|
211
|
+
// market_id: 48
|
|
212
|
+
// hot_tag: 连续11天上榜
|
|
213
|
+
// etf_product_id: "159766"
|
|
214
|
+
// rate: "10366.5"
|
|
215
|
+
// etf_name: 旅游ETF富国
|
|
216
|
+
// name: 旅游及酒店
|
|
217
|
+
// tag: 1家涨停
|
|
218
|
+
// etf_market_id: 36
|
|
219
|
+
// order: 20
|
|
220
|
+
return {
|
|
221
|
+
code: d.code,
|
|
222
|
+
name: d.name,
|
|
223
|
+
涨跌幅: d.rise_and_fall,
|
|
224
|
+
对应etf涨跌幅: d.etf_rise_and_fall,
|
|
225
|
+
热榜涨跌幅: d.hot_rank_chg,
|
|
226
|
+
热榜标签: d.hot_tag,
|
|
227
|
+
对应etf代码: d.etf_product_id,
|
|
228
|
+
讨论热度: d.rate,
|
|
229
|
+
对应etf名称: d.etf_name,
|
|
230
|
+
tag: d.tag,
|
|
231
|
+
排名: d.display_order != null ? d.display_order : d.order != null ? d.order : 0
|
|
232
|
+
};
|
|
233
|
+
});
|
|
234
|
+
} catch (err) {
|
|
235
|
+
console.error('[getPlateRank] 获取板块热榜数据失败:', err);
|
|
236
|
+
throw err;
|
|
252
237
|
}
|
|
253
|
-
const sorted = [...arr].sort((a, b) => a - b);
|
|
254
|
-
const index = Math.ceil((p / 100) * sorted.length) - 1;
|
|
255
|
-
return sorted[Math.max(0, index)];
|
|
256
238
|
}
|
|
257
239
|
|
|
258
|
-
function
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
240
|
+
function extractData(response, listKey) {
|
|
241
|
+
if (response && response.data && response.data[listKey] && Array.isArray(response.data[listKey])) {
|
|
242
|
+
return response.data[listKey];
|
|
243
|
+
}
|
|
244
|
+
if (Array.isArray(response)) {
|
|
245
|
+
return response;
|
|
262
246
|
}
|
|
247
|
+
console.warn('[extractData] 未知的数据格式:', response);
|
|
248
|
+
return [];
|
|
249
|
+
}
|
|
263
250
|
|
|
264
|
-
|
|
265
|
-
|
|
251
|
+
async function getTurnoverData(type = 'day') {
|
|
252
|
+
try {
|
|
253
|
+
const minuteData = await getTurnoverDataByMinute();
|
|
266
254
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
255
|
+
const data = await request.get('/fuyao/market_analysis_api/chart/v1/get_chart_data', {
|
|
256
|
+
chart_key: 'turnover_day'
|
|
257
|
+
});
|
|
270
258
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
}
|
|
259
|
+
if (data && data.status_code === 0 && data.data && data.data.charts) {
|
|
260
|
+
const charts = data.data.charts;
|
|
261
|
+
const pointList = charts.point_list;
|
|
275
262
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
const closes = dataCopy.map(d => d.close);
|
|
280
|
-
const {cs} = calculateEMA(DIVIDEND_SCORE_CONSTANTS.EMA_PERIOD, dataCopy);
|
|
281
|
-
const [_, ma80Bias] = calculateMA(DIVIDEND_SCORE_CONSTANTS.MA_PERIOD, dataCopy);
|
|
282
|
-
const rsi = calculateRSI(closes, DIVIDEND_SCORE_CONSTANTS.RSI_PERIOD);
|
|
283
|
-
for (let i = 0; i < dataCopy.length; i++) {
|
|
284
|
-
dataCopy[i].cs = cs[i] === '-' ? null : parseFloat(cs[i]);
|
|
285
|
-
dataCopy[i].ma80Bias = ma80Bias[i] === '-' ? null : parseFloat(ma80Bias[i]);
|
|
286
|
-
dataCopy[i].rsi = rsi[i];
|
|
287
|
-
}
|
|
263
|
+
if (!pointList || pointList.length < 2) {
|
|
264
|
+
throw new Error('数据不足');
|
|
265
|
+
}
|
|
288
266
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
267
|
+
const latest = pointList[pointList.length - 1];
|
|
268
|
+
const previous = pointList[pointList.length - 2];
|
|
269
|
+
|
|
270
|
+
const currentTurnover = latest[1];
|
|
271
|
+
const prevTurnover = previous[1];
|
|
272
|
+
const diff = currentTurnover - prevTurnover;
|
|
273
|
+
const currentYi = currentTurnover / 100000000; // 先转为亿
|
|
274
|
+
const currentWanYi = (currentYi / 10000).toFixed(2); // 再转为万亿
|
|
275
|
+
const diffYi = (Math.abs(diff) / 100000000).toFixed(2); // 转为亿
|
|
276
|
+
const formattedData = {
|
|
277
|
+
当前成交额: currentWanYi + '万亿',
|
|
278
|
+
变化量: (diff > 0 ? '增加' : '减少') + diffYi + '亿',
|
|
279
|
+
较上日: diff > 0 ? '增加' : '减少'
|
|
280
|
+
};
|
|
281
|
+
const isTrading = minuteData.isTrading;
|
|
282
|
+
// '0': { val: 1623545300000, name: '当日成交额', key: 'turnover' },
|
|
283
|
+
// '1': { val: 1668872000000, name: '昨日成交额', key: 'turnover_pre' },
|
|
284
|
+
// '2': { val: -45326700000, name: '较昨日变动', key: 'turnover_change' },
|
|
285
|
+
// '3': { val: 1623545300000, name: '预测全天成交额', key: 'predict_turnover' },
|
|
286
|
+
const rs = {};
|
|
287
|
+
minuteData.header.forEach((item, index) => {
|
|
288
|
+
rs[item.name] = item.val;
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
if (isTrading) {
|
|
292
|
+
return {
|
|
293
|
+
是否正在盘中交易: isTrading ? '是' : '否',
|
|
294
|
+
...rs,
|
|
295
|
+
minuteData
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
return {
|
|
299
|
+
...formattedData,
|
|
300
|
+
是否正在盘中交易: isTrading ? '是' : '否',
|
|
301
|
+
...rs,
|
|
302
|
+
minuteData
|
|
303
|
+
};
|
|
301
304
|
}
|
|
302
305
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
current.csScore = calculateRollingScore(
|
|
308
|
-
current.cs,
|
|
309
|
-
csHistory,
|
|
310
|
-
DIVIDEND_SCORE_CONSTANTS.PERCENTILE_LOW,
|
|
311
|
-
DIVIDEND_SCORE_CONSTANTS.PERCENTILE_HIGH
|
|
312
|
-
);
|
|
313
|
-
current.ma80Score = calculateRollingScore(
|
|
314
|
-
current.ma80Bias,
|
|
315
|
-
ma80History,
|
|
316
|
-
DIVIDEND_SCORE_CONSTANTS.PERCENTILE_LOW,
|
|
317
|
-
DIVIDEND_SCORE_CONSTANTS.PERCENTILE_HIGH
|
|
318
|
-
);
|
|
319
|
-
current.rsiScore = current.rsi;
|
|
320
|
-
|
|
321
|
-
if (current.csScore !== null && current.ma80Score !== null && current.rsiScore !== null) {
|
|
322
|
-
current.totalScore = parseFloat(
|
|
323
|
-
(
|
|
324
|
-
current.csScore * DIVIDEND_SCORE_CONSTANTS.CS_WEIGHT +
|
|
325
|
-
current.ma80Score * DIVIDEND_SCORE_CONSTANTS.MA80_WEIGHT +
|
|
326
|
-
current.rsiScore * DIVIDEND_SCORE_CONSTANTS.RSI_WEIGHT
|
|
327
|
-
).toFixed(2)
|
|
328
|
-
);
|
|
329
|
-
} else {
|
|
330
|
-
current.totalScore = null;
|
|
331
|
-
}
|
|
306
|
+
throw new Error('数据格式错误');
|
|
307
|
+
} catch (err) {
|
|
308
|
+
console.error('[getTurnoverData] 获取成交额数据失败:', err);
|
|
309
|
+
throw err;
|
|
332
310
|
}
|
|
311
|
+
}
|
|
333
312
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
313
|
+
async function getTurnoverDataByMinute() {
|
|
314
|
+
try {
|
|
315
|
+
const data = await request.get('/fuyao/market_analysis_api/chart/v1/get_chart_data', {
|
|
316
|
+
chart_key: 'turnover_minute'
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
if (data && data.status_code === 0 && data.data && data.data.charts) {
|
|
320
|
+
const charts = data.data.charts;
|
|
321
|
+
const e = formatThsVolumeTime(data.data);
|
|
322
|
+
const isTrading = isTradingNow(e.dataTimestamp);
|
|
323
|
+
return {
|
|
324
|
+
isTrading,
|
|
325
|
+
name: charts.name,
|
|
326
|
+
time: charts.mtime,
|
|
327
|
+
header: charts.header,
|
|
328
|
+
point_key_list: charts.point_key_list,
|
|
329
|
+
point_list: charts.point_list,
|
|
330
|
+
lines: charts.lines,
|
|
331
|
+
x_label_list: charts.x_label_list
|
|
332
|
+
};
|
|
339
333
|
}
|
|
340
334
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
if (scoreHistory.length >= DIVIDEND_SCORE_CONSTANTS.SCORE_MA_PERIOD) {
|
|
347
|
-
current.scoreMA = parseFloat((scoreHistory.reduce((a, b) => a + b, 0) / scoreHistory.length).toFixed(2));
|
|
348
|
-
} else {
|
|
349
|
-
current.scoreMA = current.totalScore;
|
|
350
|
-
}
|
|
335
|
+
throw new Error('数据格式错误');
|
|
336
|
+
} catch (err) {
|
|
337
|
+
console.error('[getTurnoverDataByMinute] 获取成交额数据失败:', err);
|
|
338
|
+
throw err;
|
|
351
339
|
}
|
|
352
|
-
|
|
353
|
-
return dataCopy;
|
|
354
340
|
}
|
|
355
341
|
|
|
356
342
|
module.exports = {
|
|
@@ -370,5 +356,10 @@ module.exports = {
|
|
|
370
356
|
getSecId,
|
|
371
357
|
queryStockData,
|
|
372
358
|
getPatternStocks,
|
|
373
|
-
getDividendScore
|
|
359
|
+
getDividendScore,
|
|
360
|
+
getStockRank,
|
|
361
|
+
getPlateRank,
|
|
362
|
+
getTurnoverData,
|
|
363
|
+
getTurnoverDataByMinute,
|
|
364
|
+
getFinanceReportDetail
|
|
374
365
|
};
|
package/lib/caibao.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// http://basic.10jqka.com.cn/300014/
|
|
2
|
+
// const vm = require('vm');
|
|
3
|
+
|
|
4
|
+
// ?ut=&invt=2&fltt=2&fields=&secid=1.600862&cb=&_=1601168994587
|
|
5
|
+
const picker = require('@ksky521/html-picker');
|
|
6
|
+
const iconv = require('./iconv');
|
|
7
|
+
|
|
8
|
+
const {getHeader} = require('./thsUtils');
|
|
9
|
+
|
|
10
|
+
const request = require('request-promise-native');
|
|
11
|
+
|
|
12
|
+
const API_URL = 'http://basic.10jqka.com.cn/';
|
|
13
|
+
|
|
14
|
+
function getDetail(stockId) {
|
|
15
|
+
const prefix = `${API_URL}${stockId}`;
|
|
16
|
+
const url = `${prefix}/finance.html`;
|
|
17
|
+
// console.log(url);
|
|
18
|
+
return request({
|
|
19
|
+
uri: url,
|
|
20
|
+
encoding: null,
|
|
21
|
+
headers: getHeader({Referrer: prefix})
|
|
22
|
+
}).then(data => {
|
|
23
|
+
const html = iconv(data);
|
|
24
|
+
let rs = {};
|
|
25
|
+
picker(html, {
|
|
26
|
+
data: {
|
|
27
|
+
selector: 'p#main',
|
|
28
|
+
handler($node) {
|
|
29
|
+
rs = JSON.parse($node.html());
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
const titles = rs.title;
|
|
34
|
+
const content = rs.report;
|
|
35
|
+
const reports = [];
|
|
36
|
+
for (let index = 0; index < content[0].length; index++) {
|
|
37
|
+
const report = {};
|
|
38
|
+
for (let i = 0; i < titles.length; i++) {
|
|
39
|
+
let title = titles[i];
|
|
40
|
+
if (typeof title === 'string') {
|
|
41
|
+
title = title.trim();
|
|
42
|
+
} else if (Array.isArray(title)) {
|
|
43
|
+
title = title[0];
|
|
44
|
+
}
|
|
45
|
+
if (content[index]) {
|
|
46
|
+
report[title] = content[i][index];
|
|
47
|
+
} else {
|
|
48
|
+
// console.log(report[title]);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (Object.keys(report).length > 0) {
|
|
52
|
+
reports.push(report);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// console.log(titles.length, content.length);
|
|
56
|
+
return reports;
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
module.exports = getDetail;
|
|
61
|
+
// if (require.main === module) {
|
|
62
|
+
// // getDetail('300014').then(data => console.log(data));
|
|
63
|
+
// // getDetail('600036').then(data => {
|
|
64
|
+
// // const title = data.title;
|
|
65
|
+
// // const content = data.simple;
|
|
66
|
+
// // console.log(data.title[13], content[13]);
|
|
67
|
+
// // });
|
|
68
|
+
// // getDetail('601633').then(data => console.log(data));
|
|
69
|
+
// }
|