init
This commit is contained in:
commit
fb28b7f6b1
34
.gitignore
vendored
Normal file
34
.gitignore
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
# dependencies (bun install)
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# output
|
||||||
|
out
|
||||||
|
dist
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# code coverage
|
||||||
|
coverage
|
||||||
|
*.lcov
|
||||||
|
|
||||||
|
# logs
|
||||||
|
logs
|
||||||
|
_.log
|
||||||
|
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
||||||
|
|
||||||
|
# dotenv environment variable files
|
||||||
|
.env
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
.env.local
|
||||||
|
|
||||||
|
# caches
|
||||||
|
.eslintcache
|
||||||
|
.cache
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# IntelliJ based IDEs
|
||||||
|
.idea
|
||||||
|
|
||||||
|
# Finder (MacOS) folder config
|
||||||
|
.DS_Store
|
||||||
21
README.md
Normal file
21
README.md
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# bun-react-template
|
||||||
|
|
||||||
|
To install dependencies:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun install
|
||||||
|
```
|
||||||
|
|
||||||
|
To start a development server:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun dev
|
||||||
|
```
|
||||||
|
|
||||||
|
To run for production:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun start
|
||||||
|
```
|
||||||
|
|
||||||
|
This project was created using `bun init` in bun v1.2.21. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.
|
||||||
3163
__test__/data/view-event-content.html
Normal file
3163
__test__/data/view-event-content.html
Normal file
File diff suppressed because it is too large
Load Diff
388
__test__/data/view-event.html
Normal file
388
__test__/data/view-event.html
Normal file
@ -0,0 +1,388 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||||
|
<meta http-equiv="x-ua-compatible" content="ie=7" />
|
||||||
|
<meta name="keywords" content=" 俱乐部比赛,俱乐部积分赛 " />
|
||||||
|
<meta name="description" content=" 俱乐部比赛,可以发起积分赛等活动 " />
|
||||||
|
<title>东华乒乓球俱乐部 - 比赛 - 开球网 - 全国乒乓球积分赛网站 </title>
|
||||||
|
<script language="javascript" type="text/javascript" src="source/script_cookie.js"></script>
|
||||||
|
<script language="javascript" type="text/javascript" src="source/script_common.js"></script>
|
||||||
|
<script language="javascript" type="text/javascript" src="source/script_menu.js"></script>
|
||||||
|
<script language="javascript" type="text/javascript" src="source/script_ajax.js"></script>
|
||||||
|
<script language="javascript" type="text/javascript" src="source/script_face.js"></script>
|
||||||
|
<script language="javascript" type="text/javascript" src="source/script_manage.js"></script>
|
||||||
|
<script type="text/javascript" src="js/jquery-1.7.2.min.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
var jq = jQuery.noConflict();
|
||||||
|
</script>
|
||||||
|
<style type="text/css">
|
||||||
|
@import url(template/default/style.css);
|
||||||
|
@import url(template/default/thread.css);
|
||||||
|
@import url(template/green/style.css);
|
||||||
|
</style>
|
||||||
|
<link rel="shortcut icon" href="image/favicon.ico" />
|
||||||
|
<link rel="edituri" type="application/rsd+xml" title="rsd" href="xmlrpc.php?rsd=0" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="header" style="width:100%;margin:0 0 5px;background: url('image/club_bg.jpg') repeat-x scroll left top transparent;">
|
||||||
|
<div class="mtag_headerwarp" style="height:24px; padding:0px 20px;">
|
||||||
|
<ul class="menu" style="height:20px">
|
||||||
|
<li style="padding:0 8px"><a href="index.php">首页</a></li>
|
||||||
|
<li style="padding:0 8px"><a href="network.html">主站</a></li>
|
||||||
|
<li style="padding:0 8px"><a href="space-mtag.html">俱乐部</a></li>
|
||||||
|
<li style="padding:0 8px"><a href="space-event.html">比赛</a></li>
|
||||||
|
<li style="padding:0 8px"><a href="space-score.html">积分</a></li>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="nav_account" style="height:24px; padding:0px 20px; float:right">
|
||||||
|
|
||||||
|
欢迎您
|
||||||
|
<a href="do.php?ac=668g">登录</a> |
|
||||||
|
<a href="do.php?ac=sss22">注册</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="width:984px;margin:0 auto;background-color:#FFFFFF;padding: 5px 2px 5px 2px">
|
||||||
|
<div id="append_parent"></div>
|
||||||
|
<div id="ajaxwaitid"></div>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="wrap">
|
||||||
|
|
||||||
|
|
||||||
|
<div id="mainarea" style="width:970px">
|
||||||
|
<div>
|
||||||
|
<!--<img id="clubbannerpic" src="https://www.kaiqiu.cc/home/image/my/dh2.jpg" width="968" height="323" -->
|
||||||
|
<img id="clubbannerpic" src="https://kaiqiu.oss-cn-beijing.aliyuncs.com/https://www.kaiqiu.cc/home/image/my/dh2.jpg" width="968" height="323"
|
||||||
|
style="padding:0px; background:white;border-style:solid;border-width: 0px;border-color: navy"></img>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="height:10px"></div>
|
||||||
|
|
||||||
|
|
||||||
|
<h2 class="title">
|
||||||
|
<img src="image/app/mtag.gif"><a href="space-mtag.html">俱乐部</a> - <a href="space-mtag-tagid-47.html">东华乒乓球俱乐部</a>
|
||||||
|
</h2>
|
||||||
|
<div class="tabs_header">
|
||||||
|
<a href="cp.php?ac=share&type=mtag&id=47" id="a_share" class="a_share" onclick="ajaxmenu(event, this.id, 1)">分享</a>
|
||||||
|
<div class="r_option">
|
||||||
|
<a href="cp.php?ac=common&op=report&idtype=tagid&id=47" id="a_report" onclick="ajaxmenu(event, this.id, 1)">举报</a><span class="pipe">|</span>
|
||||||
|
</div>
|
||||||
|
<ul class="tabs">
|
||||||
|
<li><a href="space-mtag-tagid-47.html"><span>首页</span></a></li>
|
||||||
|
<li><a href="space-mtag-tagid-47-view-list.html"><span>讨论区</span></a></li>
|
||||||
|
<li><a href="space-mtag-tagid-47-view-digest.html"><span>精华区</span></a></li>
|
||||||
|
<li><a href="space-mtag-tagid-47-view-action.html"><span>活动</span>
|
||||||
|
</a>
|
||||||
|
<li class="active"><a href="space-mtag-tagid-47-view-event.html"><span>比赛</span></a></li>
|
||||||
|
<li><a href="space-mtag-tagid-47-view-member-op-score.html"><span>成员&积分</span></a></li>
|
||||||
|
<li><a href="space-mtag-tagid-47-view-pic.html"><span>照片</span></a></li>
|
||||||
|
<li><a href="space-mtag-tagid-47-view-guess.html"><span>竞猜</span></a></li>
|
||||||
|
<li><a href="space-mtag-tagid-47-view-blog.html"><span>日志</span></a></li>
|
||||||
|
<li><a href="space-mtag-tagid-47-view-share.html"><span>分享</span></a></li>
|
||||||
|
<li><a href="space-mtag-tagid-47-view-poll.html"><span>投票</span></a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="event_list">
|
||||||
|
<ol>
|
||||||
|
<li>
|
||||||
|
<div class="event_icon">
|
||||||
|
<a href="space-event-id-167684.html"><img class="poster_pre" src="data/event/1.jpg" alt="2026年2月14日 东华乒乓球俱乐部2026年2月开球网ChinaTT积分赛(争霸赛)(内部比赛)" onerror="this.src='data/event/1.jpg'"></a>
|
||||||
|
</div>
|
||||||
|
<div class="event_content">
|
||||||
|
<h4 class="event_title"><a href="space-event-id-167684.html">2026年2月14日 东华乒乓球俱乐部2026年2月开球网ChinaTT积分赛(争霸赛)(内部比赛)</a><span class="gray">[个人积分赛]</span></h4>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<span class="gray">比赛开始:</span> 2月14日 10:00
|
||||||
|
|
||||||
|
</li>
|
||||||
|
<li><span class="gray">比赛地点:</span>
|
||||||
|
<a href="space.php?uid=&do=event&view=&type=&classid=&province=海外&date=">海外</a>
|
||||||
|
<a href="space.php?uid=&do=event&view=&type=&classid=&province=海外&city=日本&date=">日本</a>
|
||||||
|
</li>
|
||||||
|
<li><span class="gray">发起人:</span> <a href="space-71669.html">cldws</a></li>
|
||||||
|
<li style="margin: 5px 0 0;">979 次查看 56 人参加 58 人关注 </li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div class="event_icon">
|
||||||
|
<a href="space-event-id-157007.html"><img class="poster_pre" src="data/event/1.jpg" alt="2026年1月17日 东华乒乓球俱乐部2026年1月份开球网ChinaTT积分赛(激战赛)(内部比赛)" onerror="this.src='data/event/1.jpg'"></a>
|
||||||
|
</div>
|
||||||
|
<div class="event_content">
|
||||||
|
<h4 class="event_title"><a href="space-event-id-157007.html">2026年1月17日 东华乒乓球俱乐部2026年1月份开球网ChinaTT积分赛(激战赛)(内部比赛)</a><span class="gray">[个人积分赛]</span></h4>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<span class="gray">比赛开始:</span> 1月17日 10:00
|
||||||
|
<span class="event_state"> 已结束</span>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
<li><span class="gray">比赛地点:</span>
|
||||||
|
<a href="space.php?uid=&do=event&view=&type=&classid=&province=海外&date=">海外</a>
|
||||||
|
<a href="space.php?uid=&do=event&view=&type=&classid=&province=海外&city=日本&date=">日本</a>
|
||||||
|
</li>
|
||||||
|
<li><span class="gray">发起人:</span> <a href="space-71669.html">cldws</a></li>
|
||||||
|
<li style="margin: 5px 0 0;">5595 次查看 42 人参加 51 人关注 </li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div class="event_icon">
|
||||||
|
<a href="space-event-id-150788.html"><img class="poster_pre" src="data/event/1.jpg" alt="2025年12月13日 东华乒乓球俱乐部2025年12月开球网ChinaTT积分赛(争霸赛)(内部比赛)" onerror="this.src='data/event/1.jpg'"></a>
|
||||||
|
</div>
|
||||||
|
<div class="event_content">
|
||||||
|
<h4 class="event_title"><a href="space-event-id-150788.html">2025年12月13日 东华乒乓球俱乐部2025年12月开球网ChinaTT积分赛(争霸赛)(内部比赛)</a><span class="gray">[个人积分赛]</span></h4>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<span class="gray">比赛开始:</span> 12月13日 9:30
|
||||||
|
<span class="event_state"> 已结束</span>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
<li><span class="gray">比赛地点:</span>
|
||||||
|
<a href="space.php?uid=&do=event&view=&type=&classid=&province=海外&date=">海外</a>
|
||||||
|
<a href="space.php?uid=&do=event&view=&type=&classid=&province=海外&city=日本&date=">日本</a>
|
||||||
|
</li>
|
||||||
|
<li><span class="gray">发起人:</span> <a href="space-71669.html">cldws</a></li>
|
||||||
|
<li style="margin: 5px 0 0;">5226 次查看 49 人参加 57 人关注 </li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div class="event_icon">
|
||||||
|
<a href="space-event-id-136472.html"><img class="poster_pre" src="data/event/1.jpg" alt="2025年11月23日 东华乒乓球俱乐部2025年11月份开球网ChinaTT积分赛(激战赛)(内部比赛)" onerror="this.src='data/event/1.jpg'"></a>
|
||||||
|
</div>
|
||||||
|
<div class="event_content">
|
||||||
|
<h4 class="event_title"><a href="space-event-id-136472.html">2025年11月23日 东华乒乓球俱乐部2025年11月份开球网ChinaTT积分赛(激战赛)(内部比赛)</a><span class="gray">[个人积分赛]</span></h4>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<span class="gray">比赛开始:</span> 11月23日 10:00
|
||||||
|
<span class="event_state"> 已结束</span>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
<li><span class="gray">比赛地点:</span>
|
||||||
|
<a href="space.php?uid=&do=event&view=&type=&classid=&province=海外&date=">海外</a>
|
||||||
|
<a href="space.php?uid=&do=event&view=&type=&classid=&province=海外&city=日本&date=">日本</a>
|
||||||
|
</li>
|
||||||
|
<li><span class="gray">发起人:</span> <a href="space-71669.html">cldws</a></li>
|
||||||
|
<li style="margin: 5px 0 0;">5812 次查看 49 人参加 43 人关注 </li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div class="event_icon">
|
||||||
|
<a href="space-event-id-132570.html"><img class="poster_pre" src="data/event/1.jpg" alt="2025年10月5日 东华乒乓球俱乐部2025年10月开球网ChinaTT积分赛(争霸赛)(内部比赛)" onerror="this.src='data/event/1.jpg'"></a>
|
||||||
|
</div>
|
||||||
|
<div class="event_content">
|
||||||
|
<h4 class="event_title"><a href="space-event-id-132570.html">2025年10月5日 东华乒乓球俱乐部2025年10月开球网ChinaTT积分赛(争霸赛)(内部比赛)</a><span class="gray">[个人积分赛]</span></h4>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<span class="gray">比赛开始:</span> 10月05日 10:00
|
||||||
|
<span class="event_state"> 已结束</span>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
<li><span class="gray">比赛地点:</span>
|
||||||
|
<a href="space.php?uid=&do=event&view=&type=&classid=&province=海外&date=">海外</a>
|
||||||
|
<a href="space.php?uid=&do=event&view=&type=&classid=&province=海外&city=日本&date=">日本</a>
|
||||||
|
</li>
|
||||||
|
<li><span class="gray">发起人:</span> <a href="space-71669.html">cldws</a></li>
|
||||||
|
<li style="margin: 5px 0 0;">4610 次查看 48 人参加 56 人关注 </li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div class="event_icon">
|
||||||
|
<a href="space-event-id-126233.html"><img class="poster_pre" src="data/event/1.jpg" alt="2025年9月14日 东华乒乓球俱乐部2025年9月份开球网ChinaTT积分赛(激战赛)(内部比赛)" onerror="this.src='data/event/1.jpg'"></a>
|
||||||
|
</div>
|
||||||
|
<div class="event_content">
|
||||||
|
<h4 class="event_title"><a href="space-event-id-126233.html">2025年9月14日 东华乒乓球俱乐部2025年9月份开球网ChinaTT积分赛(激战赛)(内部比赛)</a><span class="gray">[个人积分赛]</span></h4>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<span class="gray">比赛开始:</span> 9月14日 10:00
|
||||||
|
<span class="event_state"> 已结束</span>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
<li><span class="gray">比赛地点:</span>
|
||||||
|
<a href="space.php?uid=&do=event&view=&type=&classid=&province=海外&date=">海外</a>
|
||||||
|
<a href="space.php?uid=&do=event&view=&type=&classid=&province=海外&city=日本&date=">日本</a>
|
||||||
|
</li>
|
||||||
|
<li><span class="gray">发起人:</span> <a href="space-71669.html">cldws</a></li>
|
||||||
|
<li style="margin: 5px 0 0;">6554 次查看 48 人参加 40 人关注 </li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div class="event_icon">
|
||||||
|
<a href="space-event-id-117651.html"><img class="poster_pre" src="data/event/1.jpg" alt="2025年8月24日 东华乒乓球俱乐部2025年8月开球网ChinaTT积分赛(争霸赛)(内部比赛)" onerror="this.src='data/event/1.jpg'"></a>
|
||||||
|
</div>
|
||||||
|
<div class="event_content">
|
||||||
|
<h4 class="event_title"><a href="space-event-id-117651.html">2025年8月24日 东华乒乓球俱乐部2025年8月开球网ChinaTT积分赛(争霸赛)(内部比赛)</a><span class="gray">[个人积分赛]</span></h4>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<span class="gray">比赛开始:</span> 8月24日 9:00
|
||||||
|
<span class="event_state"> 已结束</span>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
<li><span class="gray">比赛地点:</span>
|
||||||
|
<a href="space.php?uid=&do=event&view=&type=&classid=&province=海外&date=">海外</a>
|
||||||
|
<a href="space.php?uid=&do=event&view=&type=&classid=&province=海外&city=日本&date=">日本</a>
|
||||||
|
</li>
|
||||||
|
<li><span class="gray">发起人:</span> <a href="space-71669.html">cldws</a></li>
|
||||||
|
<li style="margin: 5px 0 0;">5082 次查看 48 人参加 55 人关注 </li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div class="event_icon">
|
||||||
|
<a href="space-event-id-107100.html"><img class="poster_pre" src="data/event/1.jpg" alt="2025年7月27日 东华乒乓球俱乐部2025年7月份开球网ChinaTT积分赛(激战赛)(内部比赛)" onerror="this.src='data/event/1.jpg'"></a>
|
||||||
|
</div>
|
||||||
|
<div class="event_content">
|
||||||
|
<h4 class="event_title"><a href="space-event-id-107100.html">2025年7月27日 东华乒乓球俱乐部2025年7月份开球网ChinaTT积分赛(激战赛)(内部比赛)</a><span class="gray">[个人积分赛]</span></h4>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<span class="gray">比赛开始:</span> 7月27日 10:00
|
||||||
|
<span class="event_state"> 已结束</span>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
<li><span class="gray">比赛地点:</span>
|
||||||
|
<a href="space.php?uid=&do=event&view=&type=&classid=&province=海外&date=">海外</a>
|
||||||
|
<a href="space.php?uid=&do=event&view=&type=&classid=&province=海外&city=日本&date=">日本</a>
|
||||||
|
</li>
|
||||||
|
<li><span class="gray">发起人:</span> <a href="space-71669.html">cldws</a></li>
|
||||||
|
<li style="margin: 5px 0 0;">5943 次查看 48 人参加 40 人关注 </li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div class="event_icon">
|
||||||
|
<a href="space-event-id-102102.html"><img class="poster_pre" src="data/event/1.jpg" alt="2025年6月8日 东华乒乓球俱乐部2025年6月开球网ChinaTT积分赛(争霸赛)(内部比赛)" onerror="this.src='data/event/1.jpg'"></a>
|
||||||
|
</div>
|
||||||
|
<div class="event_content">
|
||||||
|
<h4 class="event_title"><a href="space-event-id-102102.html">2025年6月8日 东华乒乓球俱乐部2025年6月开球网ChinaTT积分赛(争霸赛)(内部比赛)</a><span class="gray">[个人积分赛]</span></h4>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<span class="gray">比赛开始:</span> 6月08日 9:30
|
||||||
|
<span class="event_state"> 已结束</span>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
<li><span class="gray">比赛地点:</span>
|
||||||
|
<a href="space.php?uid=&do=event&view=&type=&classid=&province=海外&date=">海外</a>
|
||||||
|
<a href="space.php?uid=&do=event&view=&type=&classid=&province=海外&city=日本&date=">日本</a>
|
||||||
|
</li>
|
||||||
|
<li><span class="gray">发起人:</span> <a href="space-71669.html">cldws</a></li>
|
||||||
|
<li style="margin: 5px 0 0;">5347 次查看 48 人参加 53 人关注 </li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div class="event_icon">
|
||||||
|
<a href="space-event-id-95539.html"><img class="poster_pre" src="data/event/1.jpg" alt="2025年5月18日 东华乒乓球俱乐部2025年5月份开球网ChinaTT积分赛(激战赛)(内部比赛)" onerror="this.src='data/event/1.jpg'"></a>
|
||||||
|
</div>
|
||||||
|
<div class="event_content">
|
||||||
|
<h4 class="event_title"><a href="space-event-id-95539.html">2025年5月18日 东华乒乓球俱乐部2025年5月份开球网ChinaTT积分赛(激战赛)(内部比赛)</a><span class="gray">[个人积分赛]</span></h4>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<span class="gray">比赛开始:</span> 5月18日 10:00
|
||||||
|
<span class="event_state"> 已结束</span>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
<li><span class="gray">比赛地点:</span>
|
||||||
|
<a href="space.php?uid=&do=event&view=&type=&classid=&province=海外&date=">海外</a>
|
||||||
|
<a href="space.php?uid=&do=event&view=&type=&classid=&province=海外&city=日本&date=">日本</a>
|
||||||
|
</li>
|
||||||
|
<li><span class="gray">发起人:</span> <a href="space-71669.html">cldws</a></li>
|
||||||
|
<li style="margin: 5px 0 0;">5521 次查看 46 人参加 33 人关注 </li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
<div class="page"><em> 132 </em><strong>1</strong><a href="space-0-do-mtag-tagid-47-view-event-page-2.html">2</a><a href="space-0-do-mtag-tagid-47-view-event-page-3.html">3</a><a href="space-0-do-mtag-tagid-47-view-event-page-4.html">4</a><a href="space-0-do-mtag-tagid-47-view-event-page-5.html">5</a><a href="space-0-do-mtag-tagid-47-view-event-page-2.html" class="next">››</a><a href="space-0-do-mtag-tagid-47-view-event-page-14.html" class="last">... 14</a> <script type="text/javascript">
|
||||||
|
function goto(formItem){
|
||||||
|
var toURL = "space.php?uid=0&do=mtag&tagid=47&view=event&" + "page=" + formItem.value;
|
||||||
|
window.location = toURL;
|
||||||
|
}
|
||||||
|
</script>直接跳转到<select style='height:20px;padding:0px;' name='toPage' id='toPage' onchange='goto(this);'><option style='border:none;' value=1 selected="selected">1</option><option style='border:none;' value=2>2</option><option style='border:none;' value=3>3</option><option style='border:none;' value=4>4</option><option style='border:none;' value=5>5</option><option style='border:none;' value=6>6</option><option style='border:none;' value=7>7</option><option style='border:none;' value=8>8</option><option style='border:none;' value=9>9</option><option style='border:none;' value=10>10</option><option style='border:none;' value=11>11</option><option style='border:none;' value=12>12</option><option style='border:none;' value=13>13</option><option style='border:none;' value=14>14</option></select>页</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--/mainarea-->
|
||||||
|
<div style="clear:both"></div>
|
||||||
|
</div>
|
||||||
|
<!--/main-->
|
||||||
|
</div>
|
||||||
|
<div id="footer">
|
||||||
|
|
||||||
|
<p class="r_option">
|
||||||
|
<a href="javascript:;" onclick="window.scrollTo(0,0);" id="a_top" title="TOP"><img src="image/top.gif" alt="" style="padding: 5px 6px 6px;" /></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<p>
|
||||||
|
开球网 - 全国乒乓球积分赛网站 -
|
||||||
|
<a href="/cdn-cgi/l/email-protection#345550595d5a745f555d455d411a5757">联系我们</a>
|
||||||
|
- <a href="http://www.miibeian.gov.cn" target="_blank">京ICP备2025108382号-2</a> - <script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script><script type="text/javascript">
|
||||||
|
var _bdhmProtocol = (("https:" == document.location.protocol) ? " https://" : " http://");
|
||||||
|
document.write(unescape("%3Cscript src='" + _bdhmProtocol + "hm.baidu.com/h.js%3F1d16dd4ba09b8f8a869f3b9cb3248fd9' type='text/javascript'%3E%3C/script%3E"));
|
||||||
|
</script>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!--/wrap-->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script language="javascript" type="text/javascript" src="do.php?ac=sendmail&rand=1769184718"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
jq(document.body).css("background", "#FFFFFF");
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
// 微信配置
|
||||||
|
wx.config({
|
||||||
|
debug: false,
|
||||||
|
appId: 'wx083c8f7b0e56cbc6',
|
||||||
|
timestamp: ,
|
||||||
|
nonceStr: '',
|
||||||
|
signature: '',
|
||||||
|
jsapi_ticket: '',
|
||||||
|
url:'',
|
||||||
|
jsApiList: ['onMenuShareTimeline', 'onMenuShareAppMessage'] // 功能列表,我们要使用JS-SDK的什么功能
|
||||||
|
});
|
||||||
|
// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在 页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready 函数中。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
wx.ready(function(){
|
||||||
|
// 获取“分享到朋友圈”按钮点击状态及自定义分享内容接口
|
||||||
|
wx.onMenuShareTimeline({
|
||||||
|
title: '', // 分享标题
|
||||||
|
desc:'', // 分享描述
|
||||||
|
link: '', // 分享链接
|
||||||
|
imgUrl:'', // 分享图标
|
||||||
|
|
||||||
|
});
|
||||||
|
// 获取“分享给朋友”按钮点击状态及自定义分享内容接口
|
||||||
|
wx.onMenuShareAppMessage({
|
||||||
|
title: '', // 分享标题
|
||||||
|
desc:'', // 分享描述
|
||||||
|
link: '', // 分享链接
|
||||||
|
imgUrl:'', // 分享图标
|
||||||
|
type: 'link', // 分享类型,music、video或link,不填默认为link
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
18
__test__/utils.load-html.test.ts
Normal file
18
__test__/utils.load-html.test.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { expect, test } from 'bun:test';
|
||||||
|
import path from 'path';
|
||||||
|
import fs from 'fs';
|
||||||
|
import { fetchEventContentHTML, fetchEventListHTML } from '../src/utils';
|
||||||
|
|
||||||
|
test('load html', async () => {
|
||||||
|
const saveTo = path.resolve(__dirname, 'data', 'view-event.html');
|
||||||
|
const html = await fetchEventListHTML(`47`);
|
||||||
|
fs.writeFileSync(saveTo, html?? '');
|
||||||
|
expect(html?.length).not.toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('load html', async () => {
|
||||||
|
const saveTo = path.resolve(__dirname, 'data', 'view-event-content.html');
|
||||||
|
const html = await fetchEventContentHTML('167684');
|
||||||
|
fs.writeFileSync(saveTo, html?? '');
|
||||||
|
expect(html?.length).not.toBe(0);
|
||||||
|
});
|
||||||
45
__test__/utils.test.ts
Normal file
45
__test__/utils.test.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import fs from 'fs';
|
||||||
|
import { expect, test } from 'bun:test';
|
||||||
|
import path from 'path';
|
||||||
|
import { parseEventInfo, parseEventList, sneckGroup } from '../src/utils';
|
||||||
|
|
||||||
|
|
||||||
|
const matchId = '167684';
|
||||||
|
const item_id = '7098063';
|
||||||
|
test('event list not empty', () => {
|
||||||
|
const html = fs.readFileSync(path.resolve(__dirname, 'data', 'view-event.html')).toString();
|
||||||
|
const list = parseEventList(html);
|
||||||
|
expect(list.length).toBe(10);
|
||||||
|
console.log(list[0]?.matchId);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('event content not empty', () => {
|
||||||
|
const html = fs.readFileSync(
|
||||||
|
path.resolve(__dirname, 'data', 'view-event-content.html')
|
||||||
|
).toString();
|
||||||
|
const { itemId, players } = parseEventInfo(html);
|
||||||
|
expect(itemId).toBe(item_id);
|
||||||
|
expect(players.length).toBeGreaterThan(0);
|
||||||
|
console.log(players);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("group", () => {
|
||||||
|
const group = sneckGroup(12, 4);
|
||||||
|
console.log(group);
|
||||||
|
/**
|
||||||
|
* A B
|
||||||
|
* [01] [07]
|
||||||
|
* [02] [08]
|
||||||
|
* [05] [09]
|
||||||
|
* [06] [10]
|
||||||
|
* A B
|
||||||
|
* [01] [08]
|
||||||
|
* [07] [02]
|
||||||
|
* [05] [10]
|
||||||
|
* [09] [06]
|
||||||
|
*/
|
||||||
|
expect(group?.[0]?.[0]).toBe(0);
|
||||||
|
expect(group?.[0]?.[1]).toBe(6);
|
||||||
|
expect(group?.[1]?.[0]).toBe(7);
|
||||||
|
expect(group?.[1]?.[1]).toBe(1);
|
||||||
|
})
|
||||||
17
bun-env.d.ts
vendored
Normal file
17
bun-env.d.ts
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Generated by `bun init`
|
||||||
|
|
||||||
|
declare module "*.svg" {
|
||||||
|
/**
|
||||||
|
* A path to the SVG file
|
||||||
|
*/
|
||||||
|
const path: `${string}.svg`;
|
||||||
|
export = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module "*.module.css" {
|
||||||
|
/**
|
||||||
|
* A record of class names to their corresponding CSS module classes
|
||||||
|
*/
|
||||||
|
const classes: { readonly [key: string]: string };
|
||||||
|
export = classes;
|
||||||
|
}
|
||||||
191
bun.lock
Normal file
191
bun.lock
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
{
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"workspaces": {
|
||||||
|
"": {
|
||||||
|
"name": "kaiqiu-rank-list",
|
||||||
|
"dependencies": {
|
||||||
|
"@ant-design/icons": "^6.1.0",
|
||||||
|
"ahooks": "^3.9.6",
|
||||||
|
"antd": "^6.2.1",
|
||||||
|
"lodash": "^4.17.23",
|
||||||
|
"react": "^19",
|
||||||
|
"react-dom": "^19",
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bun": "latest",
|
||||||
|
"@types/lodash": "^4.17.23",
|
||||||
|
"@types/react": "^19",
|
||||||
|
"@types/react-dom": "^19",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"packages": {
|
||||||
|
"@ant-design/colors": ["@ant-design/colors@8.0.1", "", { "dependencies": { "@ant-design/fast-color": "^3.0.0" } }, "sha512-foPVl0+SWIslGUtD/xBr1p9U4AKzPhNYEseXYRRo5QSzGACYZrQbe11AYJbYfAWnWSpGBx6JjBmSeugUsD9vqQ=="],
|
||||||
|
|
||||||
|
"@ant-design/cssinjs": ["@ant-design/cssinjs@2.0.3", "", { "dependencies": { "@babel/runtime": "^7.11.1", "@emotion/hash": "^0.8.0", "@emotion/unitless": "^0.7.5", "@rc-component/util": "^1.4.0", "clsx": "^2.1.1", "csstype": "^3.1.3", "stylis": "^4.3.4" }, "peerDependencies": { "react": ">=16.0.0", "react-dom": ">=16.0.0" } }, "sha512-HAo8SZ3a6G8v6jT0suCz1270na6EA3obeJWM4uzRijBhdwdoMAXWK2f4WWkwB28yUufsfk3CAhN1coGPQq4kNQ=="],
|
||||||
|
|
||||||
|
"@ant-design/cssinjs-utils": ["@ant-design/cssinjs-utils@2.0.2", "", { "dependencies": { "@ant-design/cssinjs": "^2.0.1", "@babel/runtime": "^7.23.2", "@rc-component/util": "^1.4.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" } }, "sha512-Mq3Hm6fJuQeFNKSp3+yT4bjuhVbdrsyXE2RyfpJFL0xiYNZdaJ6oFaE3zFrzmHbmvTd2Wp3HCbRtkD4fU+v2ZA=="],
|
||||||
|
|
||||||
|
"@ant-design/fast-color": ["@ant-design/fast-color@3.0.0", "", {}, "sha512-eqvpP7xEDm2S7dUzl5srEQCBTXZMmY3ekf97zI+M2DHOYyKdJGH0qua0JACHTqbkRnD/KHFQP9J1uMJ/XWVzzA=="],
|
||||||
|
|
||||||
|
"@ant-design/icons": ["@ant-design/icons@6.1.0", "", { "dependencies": { "@ant-design/colors": "^8.0.0", "@ant-design/icons-svg": "^4.4.0", "@rc-component/util": "^1.3.0", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=16.0.0", "react-dom": ">=16.0.0" } }, "sha512-KrWMu1fIg3w/1F2zfn+JlfNDU8dDqILfA5Tg85iqs1lf8ooyGlbkA+TkwfOKKgqpUmAiRY1PTFpuOU2DAIgSUg=="],
|
||||||
|
|
||||||
|
"@ant-design/icons-svg": ["@ant-design/icons-svg@4.4.2", "", {}, "sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA=="],
|
||||||
|
|
||||||
|
"@ant-design/react-slick": ["@ant-design/react-slick@2.0.0", "", { "dependencies": { "@babel/runtime": "^7.28.4", "clsx": "^2.1.1", "json2mq": "^0.2.0", "throttle-debounce": "^5.0.0" }, "peerDependencies": { "react": "^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-HMS9sRoEmZey8LsE/Yo6+klhlzU12PisjrVcydW3So7RdklyEd2qehyU6a7Yp+OYN72mgsYs3NFCyP2lCPFVqg=="],
|
||||||
|
|
||||||
|
"@babel/runtime": ["@babel/runtime@7.28.6", "", {}, "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA=="],
|
||||||
|
|
||||||
|
"@emotion/hash": ["@emotion/hash@0.8.0", "", {}, "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow=="],
|
||||||
|
|
||||||
|
"@emotion/unitless": ["@emotion/unitless@0.7.5", "", {}, "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg=="],
|
||||||
|
|
||||||
|
"@rc-component/async-validator": ["@rc-component/async-validator@5.1.0", "", { "dependencies": { "@babel/runtime": "^7.24.4" } }, "sha512-n4HcR5siNUXRX23nDizbZBQPO0ZM/5oTtmKZ6/eqL0L2bo747cklFdZGRN2f+c9qWGICwDzrhW0H7tE9PptdcA=="],
|
||||||
|
|
||||||
|
"@rc-component/cascader": ["@rc-component/cascader@1.11.0", "", { "dependencies": { "@rc-component/select": "~1.5.0", "@rc-component/tree": "~1.1.0", "@rc-component/util": "^1.4.0", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=18.0.0", "react-dom": ">=18.0.0" } }, "sha512-VDiEsskThWi8l0/1Nquc9I4ytcMKQYAb9Jkm6wiX5O5fpcMRsm+b8OulBMbr/b4rFTl/2y2y4GdKqQ+2whD+XQ=="],
|
||||||
|
|
||||||
|
"@rc-component/checkbox": ["@rc-component/checkbox@1.0.1", "", { "dependencies": { "@rc-component/util": "^1.3.0", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, "sha512-08yTH8m+bSm8TOqbybbJ9KiAuIATti6bDs2mVeSfu4QfEnyeF6X0enHVvD1NEAyuBWEAo56QtLe++MYs2D9XiQ=="],
|
||||||
|
|
||||||
|
"@rc-component/collapse": ["@rc-component/collapse@1.2.0", "", { "dependencies": { "@babel/runtime": "^7.10.1", "@rc-component/motion": "^1.1.4", "@rc-component/util": "^1.3.0", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=18.0.0", "react-dom": ">=18.0.0" } }, "sha512-ZRYSKSS39qsFx93p26bde7JUZJshsUBEQRlRXPuJYlAiNX0vyYlF5TsAm8JZN3LcF8XvKikdzPbgAtXSbkLUkw=="],
|
||||||
|
|
||||||
|
"@rc-component/color-picker": ["@rc-component/color-picker@3.0.3", "", { "dependencies": { "@ant-design/fast-color": "^3.0.0", "@rc-component/util": "^1.3.0", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, "sha512-V7gFF9O7o5XwIWafdbOtqI4BUUkEUkgdBwp6favy3xajMX/2dDqytFaiXlcwrpq6aRyPLp5dKLAG5RFKLXMeGA=="],
|
||||||
|
|
||||||
|
"@rc-component/context": ["@rc-component/context@2.0.1", "", { "dependencies": { "@rc-component/util": "^1.3.0" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, "sha512-HyZbYm47s/YqtP6pKXNMjPEMaukyg7P0qVfgMLzr7YiFNMHbK2fKTAGzms9ykfGHSfyf75nBbgWw+hHkp+VImw=="],
|
||||||
|
|
||||||
|
"@rc-component/dialog": ["@rc-component/dialog@1.8.0", "", { "dependencies": { "@rc-component/motion": "^1.1.3", "@rc-component/portal": "^2.1.0", "@rc-component/util": "^1.5.0", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=18.0.0", "react-dom": ">=18.0.0" } }, "sha512-zGksezfULKixYCIWctIhUC2M3zUJrc81JKWbi9dJrQdPaM7J+8vSOrhLoOHHkZFpBpb2Ri6JqnSuGYb2N+FrRA=="],
|
||||||
|
|
||||||
|
"@rc-component/drawer": ["@rc-component/drawer@1.4.0", "", { "dependencies": { "@rc-component/motion": "^1.1.4", "@rc-component/portal": "^2.1.3", "@rc-component/util": "^1.2.1", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=18.0.0", "react-dom": ">=18.0.0" } }, "sha512-Zr1j1LRLDauz4a5JXHEmeYQfvEzfh4CddNa7tszyJnfd5GySYdZ5qLO63Tt2tgG4k+qi6tkFDKmcT46ikZfzbQ=="],
|
||||||
|
|
||||||
|
"@rc-component/dropdown": ["@rc-component/dropdown@1.0.2", "", { "dependencies": { "@rc-component/trigger": "^3.0.0", "@rc-component/util": "^1.2.1", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=16.11.0", "react-dom": ">=16.11.0" } }, "sha512-6PY2ecUSYhDPhkNHHb4wfeAya04WhpmUSKzdR60G+kMNVUCX2vjT/AgTS0Lz0I/K6xrPMJ3enQbwVpeN3sHCgg=="],
|
||||||
|
|
||||||
|
"@rc-component/form": ["@rc-component/form@1.6.2", "", { "dependencies": { "@rc-component/async-validator": "^5.1.0", "@rc-component/util": "^1.6.2", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, "sha512-OgIn2RAoaSBqaIgzJf/X6iflIa9LpTozci1lagLBdURDFhGA370v0+T0tXxOi8YShMjTha531sFhwtnrv+EJaQ=="],
|
||||||
|
|
||||||
|
"@rc-component/image": ["@rc-component/image@1.6.0", "", { "dependencies": { "@rc-component/motion": "^1.0.0", "@rc-component/portal": "^2.1.2", "@rc-component/util": "^1.3.0", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, "sha512-tSfn2ZE/oP082g4QIOxeehkmgnXB7R+5AFj/lIFr4k7pEuxHBdyGIq9axoCY9qea8NN0DY6p4IB/F07tLqaT5A=="],
|
||||||
|
|
||||||
|
"@rc-component/input": ["@rc-component/input@1.1.2", "", { "dependencies": { "@rc-component/util": "^1.4.0", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=16.0.0", "react-dom": ">=16.0.0" } }, "sha512-Q61IMR47piUBudgixJ30CciKIy9b1H95qe7GgEKOmSJVJXvFRWJllJfQry9tif+MX2cWFXWJf/RXz4kaCeq/Fg=="],
|
||||||
|
|
||||||
|
"@rc-component/input-number": ["@rc-component/input-number@1.6.2", "", { "dependencies": { "@rc-component/mini-decimal": "^1.0.1", "@rc-component/util": "^1.4.0", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, "sha512-Gjcq7meZlCOiWN1t1xCC+7/s85humHVokTBI7PJgTfoyw5OWF74y3e6P8PHX104g9+b54jsodFIzyaj6p8LI9w=="],
|
||||||
|
|
||||||
|
"@rc-component/mentions": ["@rc-component/mentions@1.6.0", "", { "dependencies": { "@rc-component/input": "~1.1.0", "@rc-component/menu": "~1.2.0", "@rc-component/textarea": "~1.1.0", "@rc-component/trigger": "^3.0.0", "@rc-component/util": "^1.3.0", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, "sha512-KIkQNP6habNuTsLhUv0UGEOwG67tlmE7KNIJoQZZNggEZl5lQJTytFDb69sl5CK3TDdISCTjKP3nGEBKgT61CQ=="],
|
||||||
|
|
||||||
|
"@rc-component/menu": ["@rc-component/menu@1.2.0", "", { "dependencies": { "@rc-component/motion": "^1.1.4", "@rc-component/overflow": "^1.0.0", "@rc-component/trigger": "^3.0.0", "@rc-component/util": "^1.3.0", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, "sha512-VWwDuhvYHSnTGj4n6bV3ISrLACcPAzdPOq3d0BzkeiM5cve8BEYfvkEhNoM0PLzv51jpcejeyrLXeMVIJ+QJlg=="],
|
||||||
|
|
||||||
|
"@rc-component/mini-decimal": ["@rc-component/mini-decimal@1.1.0", "", { "dependencies": { "@babel/runtime": "^7.18.0" } }, "sha512-jS4E7T9Li2GuYwI6PyiVXmxTiM6b07rlD9Ge8uGZSCz3WlzcG5ZK7g5bbuKNeZ9pgUuPK/5guV781ujdVpm4HQ=="],
|
||||||
|
|
||||||
|
"@rc-component/motion": ["@rc-component/motion@1.1.6", "", { "dependencies": { "@rc-component/util": "^1.2.0", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, "sha512-aEQobs/YA0kqRvHIPjQvOytdtdRVyhf/uXAal4chBjxDu6odHckExJzjn2D+Ju1aKK6hx3pAs6BXdV9+86xkgQ=="],
|
||||||
|
|
||||||
|
"@rc-component/mutate-observer": ["@rc-component/mutate-observer@2.0.1", "", { "dependencies": { "@rc-component/util": "^1.2.0" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, "sha512-AyarjoLU5YlxuValRi+w8JRH2Z84TBbFO2RoGWz9d8bSu0FqT8DtugH3xC3BV7mUwlmROFauyWuXFuq4IFbH+w=="],
|
||||||
|
|
||||||
|
"@rc-component/notification": ["@rc-component/notification@1.2.0", "", { "dependencies": { "@rc-component/motion": "^1.1.4", "@rc-component/util": "^1.2.1", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, "sha512-OX3J+zVU7rvoJCikjrfW7qOUp7zlDeFBK2eA3SFbGSkDqo63Sl4Ss8A04kFP+fxHSxMDIS9jYVEZtU1FNCFuBA=="],
|
||||||
|
|
||||||
|
"@rc-component/overflow": ["@rc-component/overflow@1.0.0", "", { "dependencies": { "@babel/runtime": "^7.11.1", "@rc-component/resize-observer": "^1.0.1", "@rc-component/util": "^1.4.0", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, "sha512-GSlBeoE0XTBi5cf3zl8Qh7Uqhn7v8RrlJ8ajeVpEkNe94HWy5l5BQ0Mwn2TVUq9gdgbfEMUmTX7tJFAg7mz0Rw=="],
|
||||||
|
|
||||||
|
"@rc-component/pagination": ["@rc-component/pagination@1.2.0", "", { "dependencies": { "@rc-component/util": "^1.3.0", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, "sha512-YcpUFE8dMLfSo6OARJlK6DbHHvrxz7pMGPGmC/caZSJJz6HRKHC1RPP001PRHCvG9Z/veD039uOQmazVuLJzlw=="],
|
||||||
|
|
||||||
|
"@rc-component/picker": ["@rc-component/picker@1.9.0", "", { "dependencies": { "@rc-component/overflow": "^1.0.0", "@rc-component/resize-observer": "^1.0.0", "@rc-component/trigger": "^3.6.15", "@rc-component/util": "^1.3.0", "clsx": "^2.1.1" }, "peerDependencies": { "date-fns": ">= 2.x", "dayjs": ">= 1.x", "luxon": ">= 3.x", "moment": ">= 2.x", "react": ">=16.9.0", "react-dom": ">=16.9.0" }, "optionalPeers": ["date-fns", "dayjs", "luxon", "moment"] }, "sha512-OLisdk8AWVCG9goBU1dWzuH5QlBQk8jktmQ6p0/IyBFwdKGwyIZOSjnBYo8hooHiTdl0lU+wGf/OfMtVBw02KQ=="],
|
||||||
|
|
||||||
|
"@rc-component/portal": ["@rc-component/portal@2.2.0", "", { "dependencies": { "@rc-component/util": "^1.2.1", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=18.0.0", "react-dom": ">=18.0.0" } }, "sha512-oc6FlA+uXCMiwArHsJyHcIkX4q6uKyndrPol2eWX8YPkAnztHOPsFIRtmWG4BMlGE5h7YIRE3NiaJ5VS8Lb1QQ=="],
|
||||||
|
|
||||||
|
"@rc-component/progress": ["@rc-component/progress@1.0.2", "", { "dependencies": { "@rc-component/util": "^1.2.1", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, "sha512-WZUnH9eGxH1+xodZKqdrHke59uyGZSWgj5HBM5Kwk5BrTMuAORO7VJ2IP5Qbm9aH3n9x3IcesqHHR0NWPBC7fQ=="],
|
||||||
|
|
||||||
|
"@rc-component/qrcode": ["@rc-component/qrcode@1.1.1", "", { "dependencies": { "@babel/runtime": "^7.24.7" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, "sha512-LfLGNymzKdUPjXUbRP+xOhIWY4jQ+YMj5MmWAcgcAq1Ij8XP7tRmAXqyuv96XvLUBE/5cA8hLFl9eO1JQMujrA=="],
|
||||||
|
|
||||||
|
"@rc-component/rate": ["@rc-component/rate@1.0.1", "", { "dependencies": { "@rc-component/util": "^1.3.0", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, "sha512-bkXxeBqDpl5IOC7yL7GcSYjQx9G8H+6kLYQnNZWeBYq2OYIv1MONd6mqKTjnnJYpV0cQIU2z3atdW0j1kttpTw=="],
|
||||||
|
|
||||||
|
"@rc-component/resize-observer": ["@rc-component/resize-observer@1.1.1", "", { "dependencies": { "@rc-component/util": "^1.2.0" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, "sha512-NfXXMmiR+SmUuKE1NwJESzEUYUFWIDUn2uXpxCTOLwiRUUakd62DRNFjRJArgzyFW8S5rsL4aX5XlyIXyC/vRA=="],
|
||||||
|
|
||||||
|
"@rc-component/segmented": ["@rc-component/segmented@1.3.0", "", { "dependencies": { "@babel/runtime": "^7.11.1", "@rc-component/motion": "^1.1.4", "@rc-component/util": "^1.3.0", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=16.0.0", "react-dom": ">=16.0.0" } }, "sha512-5J/bJ01mbDnoA6P/FW8SxUvKn+OgUSTZJPzCNnTBntG50tzoP7DydGhqxp7ggZXZls7me3mc2EQDXakU3iTVFg=="],
|
||||||
|
|
||||||
|
"@rc-component/select": ["@rc-component/select@1.5.1", "", { "dependencies": { "@rc-component/overflow": "^1.0.0", "@rc-component/trigger": "^3.0.0", "@rc-component/util": "^1.3.0", "@rc-component/virtual-list": "^1.0.1", "clsx": "^2.1.1" }, "peerDependencies": { "react": "*", "react-dom": "*" } }, "sha512-ARXtwfCVnpDJj1bQjh1cimUlNQkZiN72hvtL2G4mKXIYfkokYdA2Vyu2deAfY7kuHSWpmZygVuohQt6TxOYjnA=="],
|
||||||
|
|
||||||
|
"@rc-component/slider": ["@rc-component/slider@1.0.1", "", { "dependencies": { "@rc-component/util": "^1.3.0", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, "sha512-uDhEPU1z3WDfCJhaL9jfd2ha/Eqpdfxsn0Zb0Xcq1NGQAman0TWaR37OWp2vVXEOdV2y0njSILTMpTfPV1454g=="],
|
||||||
|
|
||||||
|
"@rc-component/steps": ["@rc-component/steps@1.2.2", "", { "dependencies": { "@rc-component/util": "^1.2.1", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, "sha512-/yVIZ00gDYYPHSY0JP+M+s3ZvuXLu2f9rEjQqiUDs7EcYsUYrpJ/1bLj9aI9R7MBR3fu/NGh6RM9u2qGfqp+Nw=="],
|
||||||
|
|
||||||
|
"@rc-component/switch": ["@rc-component/switch@1.0.3", "", { "dependencies": { "@rc-component/util": "^1.3.0", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, "sha512-Jgi+EbOBquje/XNdofr7xbJQZPYJP+BlPfR0h+WN4zFkdtB2EWqEfvkXJWeipflwjWip0/17rNbxEAqs8hVHfw=="],
|
||||||
|
|
||||||
|
"@rc-component/table": ["@rc-component/table@1.9.1", "", { "dependencies": { "@rc-component/context": "^2.0.1", "@rc-component/resize-observer": "^1.0.0", "@rc-component/util": "^1.1.0", "@rc-component/virtual-list": "^1.0.1", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=18.0.0", "react-dom": ">=18.0.0" } }, "sha512-FVI5ZS/GdB3BcgexfCYKi3iHhZS3Fr59EtsxORszYGrfpH1eWr33eDNSYkVfLI6tfJ7vftJDd9D5apfFWqkdJg=="],
|
||||||
|
|
||||||
|
"@rc-component/tabs": ["@rc-component/tabs@1.7.0", "", { "dependencies": { "@rc-component/dropdown": "~1.0.0", "@rc-component/menu": "~1.2.0", "@rc-component/motion": "^1.1.3", "@rc-component/resize-observer": "^1.0.0", "@rc-component/util": "^1.3.0", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, "sha512-J48cs2iBi7Ho3nptBxxIqizEliUC+ExE23faspUQKGQ550vaBlv3aGF8Epv/UB1vFWeoJDTW/dNzgIU0Qj5i/w=="],
|
||||||
|
|
||||||
|
"@rc-component/textarea": ["@rc-component/textarea@1.1.2", "", { "dependencies": { "@rc-component/input": "~1.1.0", "@rc-component/resize-observer": "^1.0.0", "@rc-component/util": "^1.3.0", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, "sha512-9rMUEODWZDMovfScIEHXWlVZuPljZ2pd1LKNjslJVitn4SldEzq5vO1CL3yy3Dnib6zZal2r2DPtjy84VVpF6A=="],
|
||||||
|
|
||||||
|
"@rc-component/tooltip": ["@rc-component/tooltip@1.4.0", "", { "dependencies": { "@rc-component/trigger": "^3.7.1", "@rc-component/util": "^1.3.0", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=18.0.0", "react-dom": ">=18.0.0" } }, "sha512-8Rx5DCctIlLI4raR0I0xHjVTf1aF48+gKCNeAAo5bmF5VoR5YED+A/XEqzXv9KKqrJDRcd3Wndpxh2hyzrTtSg=="],
|
||||||
|
|
||||||
|
"@rc-component/tour": ["@rc-component/tour@2.3.0", "", { "dependencies": { "@rc-component/portal": "^2.2.0", "@rc-component/trigger": "^3.0.0", "@rc-component/util": "^1.7.0", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, "sha512-K04K9r32kUC+auBSQfr+Fss4SpSIS9JGe56oq/ALAX0p+i2ylYOI1MgR83yBY7v96eO6ZFXcM/igCQmubps0Ow=="],
|
||||||
|
|
||||||
|
"@rc-component/tree": ["@rc-component/tree@1.1.0", "", { "dependencies": { "@rc-component/motion": "^1.0.0", "@rc-component/util": "^1.2.1", "@rc-component/virtual-list": "^1.0.1", "clsx": "^2.1.1" }, "peerDependencies": { "react": "*", "react-dom": "*" } }, "sha512-HZs3aOlvFgQdgrmURRc/f4IujiNBf4DdEeXUlkS0lPoLlx9RoqsZcF0caXIAMVb+NaWqKtGQDnrH8hqLCN5zlA=="],
|
||||||
|
|
||||||
|
"@rc-component/tree-select": ["@rc-component/tree-select@1.6.0", "", { "dependencies": { "@rc-component/select": "~1.5.0", "@rc-component/tree": "~1.1.0", "@rc-component/util": "^1.4.0", "clsx": "^2.1.1" }, "peerDependencies": { "react": "*", "react-dom": "*" } }, "sha512-UvEGmZT+gcVvRwImAZg3/sXw9nUdn4FmCs1rSIMWjEXEIAo0dTGmIyWuLCvs+1rGe9AZ7CHMPiQUEbdadwV0fw=="],
|
||||||
|
|
||||||
|
"@rc-component/trigger": ["@rc-component/trigger@3.9.0", "", { "dependencies": { "@rc-component/motion": "^1.1.4", "@rc-component/portal": "^2.2.0", "@rc-component/resize-observer": "^1.1.1", "@rc-component/util": "^1.2.1", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=18.0.0", "react-dom": ">=18.0.0" } }, "sha512-X8btpwfrT27AgrZVOz4swclhEHTZcqaHeQMXXBgveagOiakTa36uObXbdwerXffgV8G9dH1fAAE0DHtVQs8EHg=="],
|
||||||
|
|
||||||
|
"@rc-component/upload": ["@rc-component/upload@1.1.0", "", { "dependencies": { "@rc-component/util": "^1.3.0", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, "sha512-LIBV90mAnUE6VK5N4QvForoxZc4XqEYZimcp7fk+lkE4XwHHyJWxpIXQQwMU8hJM+YwBbsoZkGksL1sISWHQxw=="],
|
||||||
|
|
||||||
|
"@rc-component/util": ["@rc-component/util@1.7.0", "", { "dependencies": { "is-mobile": "^5.0.0", "react-is": "^18.2.0" }, "peerDependencies": { "react": ">=18.0.0", "react-dom": ">=18.0.0" } }, "sha512-tIvIGj4Vl6fsZFvWSkYw9sAfiCKUXMyhVz6kpKyZbwyZyRPqv2vxYZROdaO1VB4gqTNvUZFXh6i3APUiterw5g=="],
|
||||||
|
|
||||||
|
"@rc-component/virtual-list": ["@rc-component/virtual-list@1.0.2", "", { "dependencies": { "@babel/runtime": "^7.20.0", "@rc-component/resize-observer": "^1.0.1", "@rc-component/util": "^1.4.0", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, "sha512-uvTol/mH74FYsn5loDGJxo+7kjkO4i+y4j87Re1pxJBs0FaeuMuLRzQRGaXwnMcV1CxpZLi2Z56Rerj2M00fjQ=="],
|
||||||
|
|
||||||
|
"@types/bun": ["@types/bun@1.3.6", "", { "dependencies": { "bun-types": "1.3.6" } }, "sha512-uWCv6FO/8LcpREhenN1d1b6fcspAB+cefwD7uti8C8VffIv0Um08TKMn98FynpTiU38+y2dUO55T11NgDt8VAA=="],
|
||||||
|
|
||||||
|
"@types/js-cookie": ["@types/js-cookie@3.0.6", "", {}, "sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ=="],
|
||||||
|
|
||||||
|
"@types/lodash": ["@types/lodash@4.17.23", "", {}, "sha512-RDvF6wTulMPjrNdCoYRC8gNR880JNGT8uB+REUpC2Ns4pRqQJhGz90wh7rgdXDPpCczF3VGktDuFGVnz8zP7HA=="],
|
||||||
|
|
||||||
|
"@types/node": ["@types/node@25.0.10", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-zWW5KPngR/yvakJgGOmZ5vTBemDoSqF3AcV/LrO5u5wTWyEAVVh+IT39G4gtyAkh3CtTZs8aX/yRM82OfzHJRg=="],
|
||||||
|
|
||||||
|
"@types/react": ["@types/react@19.2.9", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-Lpo8kgb/igvMIPeNV2rsYKTgaORYdO1XGVZ4Qz3akwOj0ySGYMPlQWa8BaLn0G63D1aSaAQ5ldR06wCpChQCjA=="],
|
||||||
|
|
||||||
|
"@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="],
|
||||||
|
|
||||||
|
"ahooks": ["ahooks@3.9.6", "", { "dependencies": { "@babel/runtime": "^7.21.0", "@types/js-cookie": "^3.0.6", "dayjs": "^1.9.1", "intersection-observer": "^0.12.0", "js-cookie": "^3.0.5", "lodash": "^4.17.21", "react-fast-compare": "^3.2.2", "resize-observer-polyfill": "^1.5.1", "screenfull": "^5.0.0", "tslib": "^2.4.1" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Mr7f05swd5SmKlR9SZo5U6M0LsL4ErweLzpdgXjA1JPmnZ78Vr6wzx0jUtvoxrcqGKYnX0Yjc02iEASVxHFPjQ=="],
|
||||||
|
|
||||||
|
"antd": ["antd@6.2.1", "", { "dependencies": { "@ant-design/colors": "^8.0.1", "@ant-design/cssinjs": "^2.0.3", "@ant-design/cssinjs-utils": "^2.0.2", "@ant-design/fast-color": "^3.0.0", "@ant-design/icons": "^6.1.0", "@ant-design/react-slick": "~2.0.0", "@babel/runtime": "^7.28.4", "@rc-component/cascader": "~1.11.0", "@rc-component/checkbox": "~1.0.1", "@rc-component/collapse": "~1.2.0", "@rc-component/color-picker": "~3.0.3", "@rc-component/dialog": "~1.8.0", "@rc-component/drawer": "~1.4.0", "@rc-component/dropdown": "~1.0.2", "@rc-component/form": "~1.6.2", "@rc-component/image": "~1.6.0", "@rc-component/input": "~1.1.2", "@rc-component/input-number": "~1.6.2", "@rc-component/mentions": "~1.6.0", "@rc-component/menu": "~1.2.0", "@rc-component/motion": "~1.1.6", "@rc-component/mutate-observer": "^2.0.1", "@rc-component/notification": "~1.2.0", "@rc-component/pagination": "~1.2.0", "@rc-component/picker": "~1.9.0", "@rc-component/progress": "~1.0.2", "@rc-component/qrcode": "~1.1.1", "@rc-component/rate": "~1.0.1", "@rc-component/resize-observer": "^1.1.1", "@rc-component/segmented": "~1.3.0", "@rc-component/select": "~1.5.0", "@rc-component/slider": "~1.0.1", "@rc-component/steps": "~1.2.2", "@rc-component/switch": "~1.0.3", "@rc-component/table": "~1.9.1", "@rc-component/tabs": "~1.7.0", "@rc-component/textarea": "~1.1.2", "@rc-component/tooltip": "~1.4.0", "@rc-component/tour": "~2.3.0", "@rc-component/tree": "~1.1.0", "@rc-component/tree-select": "~1.6.0", "@rc-component/trigger": "^3.9.0", "@rc-component/upload": "~1.1.0", "@rc-component/util": "^1.7.0", "clsx": "^2.1.1", "dayjs": "^1.11.11", "scroll-into-view-if-needed": "^3.1.0", "throttle-debounce": "^5.0.2" }, "peerDependencies": { "react": ">=18.0.0", "react-dom": ">=18.0.0" } }, "sha512-ycw/XX7So4MdrwYKGfvZJdkGiCYUOSTebAIi+ejE95WJ138b11oy/iJg7iH0qydaD/B5sFd7Tz8XfPBuW7CRmw=="],
|
||||||
|
|
||||||
|
"bun-types": ["bun-types@1.3.6", "", { "dependencies": { "@types/node": "*" } }, "sha512-OlFwHcnNV99r//9v5IIOgQ9Uk37gZqrNMCcqEaExdkVq3Avwqok1bJFmvGMCkCE0FqzdY8VMOZpfpR3lwI+CsQ=="],
|
||||||
|
|
||||||
|
"clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],
|
||||||
|
|
||||||
|
"compute-scroll-into-view": ["compute-scroll-into-view@3.1.1", "", {}, "sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw=="],
|
||||||
|
|
||||||
|
"csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
|
||||||
|
|
||||||
|
"dayjs": ["dayjs@1.11.19", "", {}, "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw=="],
|
||||||
|
|
||||||
|
"intersection-observer": ["intersection-observer@0.12.2", "", {}, "sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg=="],
|
||||||
|
|
||||||
|
"is-mobile": ["is-mobile@5.0.0", "", {}, "sha512-Tz/yndySvLAEXh+Uk8liFCxOwVH6YutuR74utvOcu7I9Di+DwM0mtdPVZNaVvvBUM2OXxne/NhOs1zAO7riusQ=="],
|
||||||
|
|
||||||
|
"js-cookie": ["js-cookie@3.0.5", "", {}, "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw=="],
|
||||||
|
|
||||||
|
"json2mq": ["json2mq@0.2.0", "", { "dependencies": { "string-convert": "^0.2.0" } }, "sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA=="],
|
||||||
|
|
||||||
|
"lodash": ["lodash@4.17.23", "", {}, "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w=="],
|
||||||
|
|
||||||
|
"react": ["react@19.2.3", "", {}, "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA=="],
|
||||||
|
|
||||||
|
"react-dom": ["react-dom@19.2.3", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.3" } }, "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg=="],
|
||||||
|
|
||||||
|
"react-fast-compare": ["react-fast-compare@3.2.2", "", {}, "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ=="],
|
||||||
|
|
||||||
|
"react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
|
||||||
|
|
||||||
|
"resize-observer-polyfill": ["resize-observer-polyfill@1.5.1", "", {}, "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg=="],
|
||||||
|
|
||||||
|
"scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
|
||||||
|
|
||||||
|
"screenfull": ["screenfull@5.2.0", "", {}, "sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA=="],
|
||||||
|
|
||||||
|
"scroll-into-view-if-needed": ["scroll-into-view-if-needed@3.1.0", "", { "dependencies": { "compute-scroll-into-view": "^3.0.2" } }, "sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ=="],
|
||||||
|
|
||||||
|
"string-convert": ["string-convert@0.2.1", "", {}, "sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A=="],
|
||||||
|
|
||||||
|
"stylis": ["stylis@4.3.6", "", {}, "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ=="],
|
||||||
|
|
||||||
|
"throttle-debounce": ["throttle-debounce@5.0.2", "", {}, "sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A=="],
|
||||||
|
|
||||||
|
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||||
|
|
||||||
|
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
|
||||||
|
}
|
||||||
|
}
|
||||||
2
bunfig.toml
Normal file
2
bunfig.toml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[serve.static]
|
||||||
|
env = "BUN_PUBLIC_*"
|
||||||
25
package.json
Normal file
25
package.json
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"name": "bun-react-template",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "bun --hot src/index.tsx",
|
||||||
|
"build": "bun build ./src/index.html --outdir=dist --sourcemap --target=browser --minify --define:process.env.NODE_ENV='\"production\"' --env='BUN_PUBLIC_*'",
|
||||||
|
"start": "NODE_ENV=production bun src/index.tsx"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@ant-design/icons": "^6.1.0",
|
||||||
|
"ahooks": "^3.9.6",
|
||||||
|
"antd": "^6.2.1",
|
||||||
|
"lodash": "^4.17.23",
|
||||||
|
"react": "^19",
|
||||||
|
"react-dom": "^19"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bun": "latest",
|
||||||
|
"@types/lodash": "^4.17.23",
|
||||||
|
"@types/react": "^19",
|
||||||
|
"@types/react-dom": "^19"
|
||||||
|
}
|
||||||
|
}
|
||||||
32
src/App.tsx
Normal file
32
src/App.tsx
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { useCallback, useState } from "react";
|
||||||
|
import { ClubSelector } from "./components/GameSelector";
|
||||||
|
import "./index.css";
|
||||||
|
import type { IEventInfo, Player } from "./types";
|
||||||
|
import { Drawer, Tabs } from "antd";
|
||||||
|
import { PlayerList } from "./components/PlayerList";
|
||||||
|
import { GamePanel } from "./components/GamePanel";
|
||||||
|
|
||||||
|
export function App() {
|
||||||
|
const [game, setGame] = useState<IEventInfo>();
|
||||||
|
const handleGameClick = useCallback(async (game: IEventInfo) => {
|
||||||
|
console.log(game);
|
||||||
|
setGame(game);
|
||||||
|
}, []);
|
||||||
|
return (
|
||||||
|
<div className="app">
|
||||||
|
<h1>开球网俱乐部比赛名单</h1>
|
||||||
|
<ClubSelector onGameClick={handleGameClick} />
|
||||||
|
<Drawer
|
||||||
|
placement="bottom"
|
||||||
|
title={game?.title}
|
||||||
|
open={Boolean(game)}
|
||||||
|
onClose={() => setGame(undefined)}
|
||||||
|
size={'calc(100vh - 100px)'}
|
||||||
|
>
|
||||||
|
<GamePanel game={game} />
|
||||||
|
</Drawer>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
||||||
36
src/components/GamePanel.tsx
Normal file
36
src/components/GamePanel.tsx
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import type React from "react";
|
||||||
|
import type { IEventInfo, MatchInfo } from "../types";
|
||||||
|
import { useRequest } from "ahooks";
|
||||||
|
import { Spin, Tabs } from "antd";
|
||||||
|
import { PlayerList } from "./PlayerList";
|
||||||
|
import { GroupingPrediction } from "./GroupingPrediction";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
game?: IEventInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const GamePanel: React.FC<Props> = props => {
|
||||||
|
const fetchPlayers = useRequest<MatchInfo | null, []>(async () => {
|
||||||
|
if (!props.game) return null;
|
||||||
|
const info: MatchInfo = await (await fetch(`/api/match/${props.game.matchId}`)).json();
|
||||||
|
return info;
|
||||||
|
}, { refreshDeps: [props] });
|
||||||
|
return (
|
||||||
|
<Spin spinning={fetchPlayers.loading}>
|
||||||
|
<Tabs
|
||||||
|
items={fetchPlayers.loading ? [] : [
|
||||||
|
{
|
||||||
|
key: 'groups',
|
||||||
|
label: '分组预测',
|
||||||
|
children: <GroupingPrediction players={fetchPlayers.data?.players} />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'players',
|
||||||
|
label: '运动员',
|
||||||
|
children: <PlayerList players={fetchPlayers.data?.players} />
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Spin>
|
||||||
|
);
|
||||||
|
}
|
||||||
55
src/components/GameSelector/GameSelector.tsx
Normal file
55
src/components/GameSelector/GameSelector.tsx
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import { Button, Card, Divider, Select, Space, Spin, Typography } from 'antd';
|
||||||
|
import type React from 'react';
|
||||||
|
import { clubs } from './clubList';
|
||||||
|
import { useCallback, useState } from 'react';
|
||||||
|
import { useRequest } from 'ahooks';
|
||||||
|
import { GlobalOutlined } from '@ant-design/icons';
|
||||||
|
import type { IEventInfo } from '../../types';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
onGameClick?: (info: IEventInfo) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const GameSelector: React.FC<Props> = props => {
|
||||||
|
const requestEvents = useRequest<IEventInfo[], [string]>(
|
||||||
|
async (clubId: string) => (await fetch(`/api/events/${clubId}`)).json()
|
||||||
|
, { manual: true })
|
||||||
|
const [gameList, setGameList] = useState<IEventInfo[]>([]);
|
||||||
|
const [isEmpty, setIsEmpty] = useState(false);
|
||||||
|
const handleClubChange = useCallback(async (clubId: string) => {
|
||||||
|
const list = await requestEvents.runAsync(clubId);
|
||||||
|
const activeList = list.filter(e => !e.info.join('').includes('已结束'));
|
||||||
|
setGameList(activeList);
|
||||||
|
setIsEmpty(activeList.length === 0);
|
||||||
|
}, []);
|
||||||
|
return (
|
||||||
|
<Space orientation='vertical' style={{ width: '100%' }}>
|
||||||
|
<Select
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
placeholder={'请选择俱乐部'}
|
||||||
|
size='large'
|
||||||
|
options={clubs.map(e => ({ label: e.name, value: e.clubId }))}
|
||||||
|
onChange={handleClubChange}
|
||||||
|
/>
|
||||||
|
<Divider />
|
||||||
|
{isEmpty && (<Typography.Text type='secondary'>没有未开始的比赛</Typography.Text>)}
|
||||||
|
<Spin spinning={requestEvents.loading}>
|
||||||
|
{gameList.map(e => (
|
||||||
|
<Card
|
||||||
|
key={e.matchId}
|
||||||
|
title={e.title}
|
||||||
|
hoverable
|
||||||
|
onClick={() => props.onGameClick?.(e)}
|
||||||
|
>
|
||||||
|
<Typography.Text type='success'>{e.title}</Typography.Text>
|
||||||
|
{e.info.map(e => (
|
||||||
|
<div key={e}>
|
||||||
|
<Typography.Text type='secondary'>{e}</Typography.Text>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</Spin>
|
||||||
|
</Space>
|
||||||
|
);
|
||||||
|
}
|
||||||
6
src/components/GameSelector/clubList.ts
Normal file
6
src/components/GameSelector/clubList.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export const clubs = [
|
||||||
|
{
|
||||||
|
name: '东华',
|
||||||
|
clubId: '47',
|
||||||
|
},
|
||||||
|
]
|
||||||
1
src/components/GameSelector/index.ts
Normal file
1
src/components/GameSelector/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { GameSelector as ClubSelector } from './GameSelector';
|
||||||
36
src/components/GroupMember.tsx
Normal file
36
src/components/GroupMember.tsx
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { Card, Space, Table, Typography } from "antd";
|
||||||
|
import type { Player } from "../types";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
index: number;
|
||||||
|
players?: Player[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const GroupMember: React.FC<Props> = props => {
|
||||||
|
const char = useMemo(() => {
|
||||||
|
const baseCode = 'A'.charCodeAt(0);
|
||||||
|
let idx = props.index;
|
||||||
|
const times = Math.floor(idx / 26);
|
||||||
|
const code = 'A'.repeat(times);
|
||||||
|
const lastChar = baseCode + (idx % 26);
|
||||||
|
return `${code}${String.fromCharCode(lastChar)}`;
|
||||||
|
}, []);
|
||||||
|
return (
|
||||||
|
<Card title={`${char} 组`} style={{ minWidth: 300 }}>
|
||||||
|
<Table
|
||||||
|
size="small"
|
||||||
|
rowKey={e => `${e.name}-${e.score}`}
|
||||||
|
showHeader={false}
|
||||||
|
pagination={false}
|
||||||
|
dataSource={props.players}
|
||||||
|
columns={[
|
||||||
|
{ dataIndex: '_', render: (_, __, i) => `(${i + 1})` },
|
||||||
|
{ dataIndex: 'index' },
|
||||||
|
{ dataIndex: 'name' },
|
||||||
|
{ dataIndex: 'score' },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
66
src/components/GroupingPrediction.tsx
Normal file
66
src/components/GroupingPrediction.tsx
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import React, { useMemo, useState } from "react";
|
||||||
|
import { Flex, Form, InputNumber, Space, Switch } from "antd";
|
||||||
|
import { chunk } from 'lodash';
|
||||||
|
import type { Player } from "../types";
|
||||||
|
import { GroupMember } from "./GroupMember";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
players?: Player[];
|
||||||
|
}
|
||||||
|
export const GroupingPrediction: React.FC<Props> = props => {
|
||||||
|
const [maxSize, setMaxSize] = useState(props.players?.length || 100);
|
||||||
|
const players: (Player & { index: number })[] = useMemo(() => {
|
||||||
|
return props.players?.slice(0, maxSize)?.map((e, i) => ({ ...e, index: i + 1 })) ?? [];
|
||||||
|
}, [props.players, maxSize]);
|
||||||
|
const [groupLen, setGroupLen] = useState(6);
|
||||||
|
const [sneckMode, setSneckMode] = useState(false);
|
||||||
|
const chunkSize = useMemo(() => Math.floor((players.length ?? 0) / groupLen) || 1, [players, groupLen]);
|
||||||
|
const grouped = useMemo(() => {
|
||||||
|
return chunk(players, chunkSize);
|
||||||
|
}, [chunkSize]);
|
||||||
|
const sneckGroup = useMemo(() => {
|
||||||
|
const newGroups = new Array<Player[]>(groupLen).fill([]).map(() => ([] as Player[]));
|
||||||
|
const maxTimes = Math.max(...grouped.map(e => e.length));
|
||||||
|
for (let i = 0; i < maxTimes; i++) {
|
||||||
|
grouped.forEach((group, idx) => {
|
||||||
|
const player = group[i];
|
||||||
|
if (player) {
|
||||||
|
newGroups[i]?.push(player);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return newGroups;
|
||||||
|
}, [grouped, groupLen, maxSize]);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Form layout='horizontal'>
|
||||||
|
<Form.Item label={'取人数'}>
|
||||||
|
<InputNumber
|
||||||
|
value={maxSize}
|
||||||
|
onChange={e => setMaxSize(e || props.players?.length || 0)}
|
||||||
|
max={props.players?.length}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label="分组数">
|
||||||
|
<InputNumber
|
||||||
|
value={groupLen}
|
||||||
|
onChange={e => setGroupLen(e ?? 1)}
|
||||||
|
min={1}
|
||||||
|
max={26}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label="蛇形分组">
|
||||||
|
<Switch checked={sneckMode} onChange={setSneckMode} />
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
<Flex gap='middle' wrap align="center" justify="center">
|
||||||
|
<React.Fragment key={'normal'}>
|
||||||
|
{ !sneckMode && grouped.map((p, i) => <GroupMember key={i} players={p} index={i} />)}
|
||||||
|
</React.Fragment>
|
||||||
|
<React.Fragment key={'sneck'}>
|
||||||
|
{ sneckMode && sneckGroup.map((p, i) => <GroupMember key={i} players={p} index={i} />)}
|
||||||
|
</React.Fragment>
|
||||||
|
</Flex>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
27
src/components/PlayerList.tsx
Normal file
27
src/components/PlayerList.tsx
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import type React from "react";
|
||||||
|
import type { Player } from "../types";
|
||||||
|
import { Avatar, Table } from "antd";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
loading?: boolean;
|
||||||
|
players?: Player[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PlayerList: React.FC<Props> = props => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Table
|
||||||
|
dataSource={props.players}
|
||||||
|
rowKey={(e, i) => `${e.name}-${i}`}
|
||||||
|
loading={props.loading}
|
||||||
|
>
|
||||||
|
<Table.Column width={32} dataIndex={'_'} align="center" render={(_, __, i) => `${i + 1}`} />
|
||||||
|
<Table.Column width={32} dataIndex={'avatar'} align="center" render={src => <Avatar src={src} />} />
|
||||||
|
<Table.Column width={200} title="姓名" align="center" dataIndex={'name'} />
|
||||||
|
<Table.Column width={200} dataIndex={'score'} title="积分" sorter={{
|
||||||
|
compare: ({ score: a }: Player, { score: b}: Player) => a - b,
|
||||||
|
}} />
|
||||||
|
</Table>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
31
src/frontend.tsx
Normal file
31
src/frontend.tsx
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* This file is the entry point for the React app, it sets up the root
|
||||||
|
* element and renders the App component to the DOM.
|
||||||
|
*
|
||||||
|
* It is included in `src/index.html`.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { StrictMode } from "react";
|
||||||
|
import { createRoot } from "react-dom/client";
|
||||||
|
import { App } from "./App";
|
||||||
|
import { ConfigProvider, theme } from "antd";
|
||||||
|
|
||||||
|
const elem = document.getElementById("root")!;
|
||||||
|
const app = (
|
||||||
|
<StrictMode>
|
||||||
|
<ConfigProvider theme={{
|
||||||
|
algorithm: theme.darkAlgorithm,
|
||||||
|
}}>
|
||||||
|
<App />
|
||||||
|
</ConfigProvider>
|
||||||
|
</StrictMode>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (import.meta.hot) {
|
||||||
|
// With hot module reloading, `import.meta.hot.data` is persisted.
|
||||||
|
const root = (import.meta.hot.data.root ??= createRoot(elem));
|
||||||
|
root.render(app);
|
||||||
|
} else {
|
||||||
|
// The hot module reloading API is not available in production.
|
||||||
|
createRoot(elem).render(app);
|
||||||
|
}
|
||||||
1
src/global.d.ts
vendored
Normal file
1
src/global.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
declare module "*.css";
|
||||||
44
src/index.css
Normal file
44
src/index.css
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
:root {
|
||||||
|
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||||
|
line-height: 1.5;
|
||||||
|
color-scheme: light dark;
|
||||||
|
color: rgba(255, 255, 255, 0.87);
|
||||||
|
background-color: #242424;
|
||||||
|
}
|
||||||
|
#root {
|
||||||
|
width: 100vw;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
margin: 0 auto;
|
||||||
|
display: grid;
|
||||||
|
min-width: 320px;
|
||||||
|
min-height: 100vh;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
body::before {
|
||||||
|
content: "";
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: -1;
|
||||||
|
opacity: 0.05;
|
||||||
|
background: url("./logo.svg");
|
||||||
|
background-size: 256px;
|
||||||
|
transform: rotate(-12deg) scale(1.35);
|
||||||
|
animation: slide 30s linear infinite;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
@keyframes slide {
|
||||||
|
from {
|
||||||
|
background-position: 0 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
background-position: 256px 224px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.app {
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 2rem;
|
||||||
|
text-align: center;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
14
src/index.html
Normal file
14
src/index.html
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
|
||||||
|
|
||||||
|
<link rel="icon" type="image/svg+xml" href="./logo.svg" />
|
||||||
|
<title>Bun + React</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
<script type="module" src="./frontend.tsx"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
53
src/index.tsx
Normal file
53
src/index.tsx
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import { serve } from "bun";
|
||||||
|
import index from "./index.html";
|
||||||
|
import { getMatchInfo, listEvent } from "./utils";
|
||||||
|
|
||||||
|
const server = serve({
|
||||||
|
routes: {
|
||||||
|
// Serve index.html for all unmatched routes.
|
||||||
|
"/*": index,
|
||||||
|
"/api/events/:clubid": {
|
||||||
|
async GET(req) {
|
||||||
|
const data = await listEvent(req.params.clubid);
|
||||||
|
return Response.json(data);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/match/:matchId": {
|
||||||
|
async GET(req) {
|
||||||
|
const data = await getMatchInfo(req.params.matchId);
|
||||||
|
return Response.json(data);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/hello": {
|
||||||
|
async GET(req) {
|
||||||
|
return Response.json({
|
||||||
|
message: "Hello, world!",
|
||||||
|
method: "GET",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
async PUT(req) {
|
||||||
|
return Response.json({
|
||||||
|
message: "Hello, world!",
|
||||||
|
method: "PUT",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"/api/hello/:name": async req => {
|
||||||
|
const name = req.params.name;
|
||||||
|
return Response.json({
|
||||||
|
message: `Hello, ${name}!`,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
development: process.env.NODE_ENV !== "production" && {
|
||||||
|
// Enable browser hot reloading in development
|
||||||
|
hmr: true,
|
||||||
|
|
||||||
|
// Echo console logs from the browser to the server
|
||||||
|
console: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`🚀 Server running at ${server.url}`);
|
||||||
1
src/logo.svg
Normal file
1
src/logo.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg id="Bun" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 80 70"><title>Bun Logo</title><path id="Shadow" d="M71.09,20.74c-.16-.17-.33-.34-.5-.5s-.33-.34-.5-.5-.33-.34-.5-.5-.33-.34-.5-.5-.33-.34-.5-.5-.33-.34-.5-.5-.33-.34-.5-.5A26.46,26.46,0,0,1,75.5,35.7c0,16.57-16.82,30.05-37.5,30.05-11.58,0-21.94-4.23-28.83-10.86l.5.5.5.5.5.5.5.5.5.5.5.5.5.5C19.55,65.3,30.14,69.75,42,69.75c20.68,0,37.5-13.48,37.5-30C79.5,32.69,76.46,26,71.09,20.74Z"/><g id="Body"><path id="Background" d="M73,35.7c0,15.21-15.67,27.54-35,27.54S3,50.91,3,35.7C3,26.27,9,17.94,18.22,13S33.18,3,38,3s8.94,4.13,19.78,10C67,17.94,73,26.27,73,35.7Z" style="fill:#fbf0df"/><path id="Bottom_Shadow" data-name="Bottom Shadow" d="M73,35.7a21.67,21.67,0,0,0-.8-5.78c-2.73,33.3-43.35,34.9-59.32,24.94A40,40,0,0,0,38,63.24C57.3,63.24,73,50.89,73,35.7Z" style="fill:#f6dece"/><path id="Light_Shine" data-name="Light Shine" d="M24.53,11.17C29,8.49,34.94,3.46,40.78,3.45A9.29,9.29,0,0,0,38,3c-2.42,0-5,1.25-8.25,3.13-1.13.66-2.3,1.39-3.54,2.15-2.33,1.44-5,3.07-8,4.7C8.69,18.13,3,26.62,3,35.7c0,.4,0,.8,0,1.19C9.06,15.48,20.07,13.85,24.53,11.17Z" style="fill:#fffefc"/><path id="Top" d="M35.12,5.53A16.41,16.41,0,0,1,29.49,18c-.28.25-.06.73.3.59,3.37-1.31,7.92-5.23,6-13.14C35.71,5,35.12,5.12,35.12,5.53Zm2.27,0A16.24,16.24,0,0,1,39,19c-.12.35.31.65.55.36C41.74,16.56,43.65,11,37.93,5,37.64,4.74,37.19,5.14,37.39,5.49Zm2.76-.17A16.42,16.42,0,0,1,47,17.12a.33.33,0,0,0,.65.11c.92-3.49.4-9.44-7.17-12.53C40.08,4.54,39.82,5.08,40.15,5.32ZM21.69,15.76a16.94,16.94,0,0,0,10.47-9c.18-.36.75-.22.66.18-1.73,8-7.52,9.67-11.12,9.45C21.32,16.4,21.33,15.87,21.69,15.76Z" style="fill:#ccbea7;fill-rule:evenodd"/><path id="Outline" d="M38,65.75C17.32,65.75.5,52.27.5,35.7c0-10,6.18-19.33,16.53-24.92,3-1.6,5.57-3.21,7.86-4.62,1.26-.78,2.45-1.51,3.6-2.19C32,1.89,35,.5,38,.5s5.62,1.2,8.9,3.14c1,.57,2,1.19,3.07,1.87,2.49,1.54,5.3,3.28,9,5.27C69.32,16.37,75.5,25.69,75.5,35.7,75.5,52.27,58.68,65.75,38,65.75ZM38,3c-2.42,0-5,1.25-8.25,3.13-1.13.66-2.3,1.39-3.54,2.15-2.33,1.44-5,3.07-8,4.7C8.69,18.13,3,26.62,3,35.7,3,50.89,18.7,63.25,38,63.25S73,50.89,73,35.7C73,26.62,67.31,18.13,57.78,13,54,11,51.05,9.12,48.66,7.64c-1.09-.67-2.09-1.29-3-1.84C42.63,4,40.42,3,38,3Z"/></g><g id="Mouth"><g id="Background-2" data-name="Background"><path d="M45.05,43a8.93,8.93,0,0,1-2.92,4.71,6.81,6.81,0,0,1-4,1.88A6.84,6.84,0,0,1,34,47.71,8.93,8.93,0,0,1,31.12,43a.72.72,0,0,1,.8-.81H44.26A.72.72,0,0,1,45.05,43Z" style="fill:#b71422"/></g><g id="Tongue"><path id="Background-3" data-name="Background" d="M34,47.79a6.91,6.91,0,0,0,4.12,1.9,6.91,6.91,0,0,0,4.11-1.9,10.63,10.63,0,0,0,1-1.07,6.83,6.83,0,0,0-4.9-2.31,6.15,6.15,0,0,0-5,2.78C33.56,47.4,33.76,47.6,34,47.79Z" style="fill:#ff6164"/><path id="Outline-2" data-name="Outline" d="M34.16,47a5.36,5.36,0,0,1,4.19-2.08,6,6,0,0,1,4,1.69c.23-.25.45-.51.66-.77a7,7,0,0,0-4.71-1.93,6.36,6.36,0,0,0-4.89,2.36A9.53,9.53,0,0,0,34.16,47Z"/></g><path id="Outline-3" data-name="Outline" d="M38.09,50.19a7.42,7.42,0,0,1-4.45-2,9.52,9.52,0,0,1-3.11-5.05,1.2,1.2,0,0,1,.26-1,1.41,1.41,0,0,1,1.13-.51H44.26a1.44,1.44,0,0,1,1.13.51,1.19,1.19,0,0,1,.25,1h0a9.52,9.52,0,0,1-3.11,5.05A7.42,7.42,0,0,1,38.09,50.19Zm-6.17-7.4c-.16,0-.2.07-.21.09a8.29,8.29,0,0,0,2.73,4.37A6.23,6.23,0,0,0,38.09,49a6.28,6.28,0,0,0,3.65-1.73,8.3,8.3,0,0,0,2.72-4.37.21.21,0,0,0-.2-.09Z"/></g><g id="Face"><ellipse id="Right_Blush" data-name="Right Blush" cx="53.22" cy="40.18" rx="5.85" ry="3.44" style="fill:#febbd0"/><ellipse id="Left_Bluch" data-name="Left Bluch" cx="22.95" cy="40.18" rx="5.85" ry="3.44" style="fill:#febbd0"/><path id="Eyes" d="M25.7,38.8a5.51,5.51,0,1,0-5.5-5.51A5.51,5.51,0,0,0,25.7,38.8Zm24.77,0A5.51,5.51,0,1,0,45,33.29,5.5,5.5,0,0,0,50.47,38.8Z" style="fill-rule:evenodd"/><path id="Iris" d="M24,33.64a2.07,2.07,0,1,0-2.06-2.07A2.07,2.07,0,0,0,24,33.64Zm24.77,0a2.07,2.07,0,1,0-2.06-2.07A2.07,2.07,0,0,0,48.75,33.64Z" style="fill:#fff;fill-rule:evenodd"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 3.8 KiB |
8
src/react.svg
Normal file
8
src/react.svg
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-11.5 -10.23174 23 20.46348">
|
||||||
|
<circle cx="0" cy="0" r="2.05" fill="#61dafb"/>
|
||||||
|
<g stroke="#61dafb" stroke-width="1" fill="none">
|
||||||
|
<ellipse rx="11" ry="4.2"/>
|
||||||
|
<ellipse rx="11" ry="4.2" transform="rotate(60)"/>
|
||||||
|
<ellipse rx="11" ry="4.2" transform="rotate(120)"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 338 B |
18
src/types.ts
Normal file
18
src/types.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
export interface IEventInfo {
|
||||||
|
title: string;
|
||||||
|
info: string[];
|
||||||
|
url: string;
|
||||||
|
matchId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Player {
|
||||||
|
name: string;
|
||||||
|
score: number;
|
||||||
|
avatar: string;
|
||||||
|
info: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MatchInfo {
|
||||||
|
itemId: string;
|
||||||
|
players: Player[];
|
||||||
|
}
|
||||||
112
src/utils.ts
Normal file
112
src/utils.ts
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
import { fetch } from 'bun';
|
||||||
|
import type { IEventInfo, Player } from "./types";
|
||||||
|
import * as cheerio from "cheerio";
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import { chunk } from 'lodash';
|
||||||
|
|
||||||
|
const BASE_URL = `https://kaiqiuwang.cc`;
|
||||||
|
/**
|
||||||
|
* @param tagid 俱乐部 ID
|
||||||
|
*/
|
||||||
|
export async function listEvent(tagid: string): Promise<IEventInfo[]> {
|
||||||
|
// return parseEventList(await fetchEventListHTML(tagid));
|
||||||
|
return parseEventList(
|
||||||
|
fs.readFileSync(
|
||||||
|
path.resolve(__dirname, '..', '__test__', 'data', 'view-event.html')
|
||||||
|
).toString()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param tagid 俱乐部 ID
|
||||||
|
* @return HTML
|
||||||
|
*/
|
||||||
|
export async function fetchEventListHTML(tagid: string) {
|
||||||
|
const url = `${BASE_URL}/home/space.php?do=mtag&tagid=${tagid}&view=event`;
|
||||||
|
const resp = await fetch(url);
|
||||||
|
return resp.text() ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseEventList(html: string) {
|
||||||
|
const $ = cheerio.load(html);
|
||||||
|
const blockList = $('div.event_list > ol > li');
|
||||||
|
const list: IEventInfo[] = [];
|
||||||
|
for (const block of blockList) {
|
||||||
|
const titleEl = $(block).find('.event_title');
|
||||||
|
const title = titleEl.text();
|
||||||
|
const url = $(titleEl).find('a').attr('href') ?? '';
|
||||||
|
const startDate = $(block).find('ul li:nth-of-type(1)').text().replace('比赛开始: \\t', '').trim();
|
||||||
|
const place = $(block).find('ul li:nth-of-type(2)').text().replace('比赛地点: \\t', '').trim();
|
||||||
|
const event: IEventInfo = {
|
||||||
|
title,
|
||||||
|
info: [startDate, place],
|
||||||
|
url: `${BASE_URL}/home/${url}`,
|
||||||
|
matchId: /\S+-(\d+).html$/.exec(url)?.[1] ?? '',
|
||||||
|
}
|
||||||
|
list.push(event);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param matchId 比赛 ID
|
||||||
|
* @returns HTML
|
||||||
|
*/
|
||||||
|
export async function fetchEventContentHTML(matchId: string) {
|
||||||
|
const url = `${BASE_URL}/home/space.php?do=event&id=${matchId}&view=member&status=2`;
|
||||||
|
const resp = await fetch(url);
|
||||||
|
return resp.text() ?? ''
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseEventInfo(html: string) {
|
||||||
|
const $ = cheerio.load(html);
|
||||||
|
const itemHref = $('.sub_menu a.active').attr('href') ?? '';
|
||||||
|
const itemId = /\S+item_id=(\d+)$/.exec(itemHref)?.[1] ?? '';
|
||||||
|
const players: Player[] = [];
|
||||||
|
const playersEl = $('.thumb');
|
||||||
|
for (const player of playersEl) {
|
||||||
|
const img = $(player).find('.image img').attr('src') ?? '';
|
||||||
|
const name = $(player).find('h6').text().trim();
|
||||||
|
const info = $(player).find('p:nth-of-type(2)').text().replace(/\s/g, '');
|
||||||
|
const score = Number(/^.*?\b(\d+)\b/.exec(info)?.[1]);
|
||||||
|
players.push({ name, avatar: img, score, info });
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
itemId,
|
||||||
|
players,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getMatchInfo(matchId: string) {
|
||||||
|
// return parseEventInfo(await fetchEventContentHTML(matchId));
|
||||||
|
return parseEventInfo(
|
||||||
|
fs
|
||||||
|
.readFileSync(
|
||||||
|
path.resolve(__dirname, '..', '__test__', 'data', 'view-event-content.html')
|
||||||
|
)
|
||||||
|
.toString()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function sneckGroup(size: number, groupLen: number) {
|
||||||
|
const indexArray = new Array<number>(size).fill(0).map((_, i) => i);
|
||||||
|
const group = chunk(indexArray, Math.floor((size / groupLen)));
|
||||||
|
const reversedGroup = group.map((e, i) => {
|
||||||
|
if (i % 2 === 0) return e;
|
||||||
|
return e.toReversed();
|
||||||
|
});
|
||||||
|
const times = Math.max(...reversedGroup.map(e => e.length));
|
||||||
|
const newGroups = [];
|
||||||
|
for (let row = 0; 0 < times; row++) {
|
||||||
|
const g = [];
|
||||||
|
for (let col = 0; col < groupLen; col++) {
|
||||||
|
const data = group[row]?.[col];
|
||||||
|
g.push(data);
|
||||||
|
}
|
||||||
|
newGroups.push(g);
|
||||||
|
}
|
||||||
|
console.log('newGroups', newGroups);
|
||||||
|
return newGroups;
|
||||||
|
}
|
||||||
29
tsconfig.json
Normal file
29
tsconfig.json
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
// Environment setup & latest features
|
||||||
|
"lib": ["ESNext", "DOM"],
|
||||||
|
"target": "ESNext",
|
||||||
|
"module": "Preserve",
|
||||||
|
"moduleDetection": "force",
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"allowJs": true,
|
||||||
|
|
||||||
|
// Bundler mode
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"verbatimModuleSyntax": true,
|
||||||
|
"noEmit": true,
|
||||||
|
|
||||||
|
// Best practices
|
||||||
|
"strict": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"noUncheckedIndexedAccess": true,
|
||||||
|
"noImplicitOverride": true,
|
||||||
|
|
||||||
|
// Some stricter flags (disabled by default)
|
||||||
|
"noUnusedLocals": false,
|
||||||
|
"noUnusedParameters": false,
|
||||||
|
"noPropertyAccessFromIndexSignature": false
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user