├── .gitignore ├── LICENSE ├── README.md └── src ├── backend.py ├── frontend ├── .gitignore ├── README.md ├── package-lock.json ├── package.json ├── patches │ └── shards-ui+2.1.2.patch ├── public │ ├── favicon.ico │ ├── gtag.js │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ ├── rawdata_1.0.1.json │ ├── rawdata_1.0.2-1.json │ ├── rawdata_1.0.2-2.json │ ├── rawdata_1.0.2.json │ └── robots.txt └── src │ ├── App.css │ ├── App.js │ ├── App.test.js │ ├── MainContent.js │ ├── MainNavBar.js │ ├── data │ ├── jwgl.json │ └── jwgl_has_data.json │ ├── index.css │ ├── index.js │ ├── logo.svg │ ├── serviceWorker.js │ └── setupTests.js └── utils ├── jwgl.py ├── parse_xls.py └── run.example.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Name1e5s 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WhereToSleep 2 | 呐、今天去哪个空教室睡觉呢? 3 | 4 | ### 文件结构 5 | 6 | ``` 7 | . 8 | ├── LICENSE 9 | ├── README.md 10 | └── src 11 | ├── backend.py 后端部分,使用 FastAPI 实现 12 | ├── frontend 前端部分,使用 React 胡乱实现 13 | └── utils 数据处理,在此将教务处的课表转换为后端需要的 json 文件 14 | ``` 15 | 16 | 以上代码仅在 macOS Catalina 上使用最新的 Python 测试过。 -------------------------------------------------------------------------------- /src/backend.py: -------------------------------------------------------------------------------- 1 | """后端程序,使用 SLEEP_LIST= uvicorn backend:app --host 0.0.0.0 --port 4514 启动""" 2 | import copy 3 | import json 4 | import os 5 | 6 | from fastapi import FastAPI, Query 7 | from fastapi.middleware.cors import CORSMiddleware 8 | 9 | from starlette.exceptions import HTTPException 10 | from starlette.status import HTTP_404_NOT_FOUND 11 | 12 | from typing import List, Tuple, Dict 13 | 14 | decoded_data = {} 15 | jwgl_data = {} 16 | 17 | 18 | def to_tuple(data: Dict) -> Tuple[str, str, str]: 19 | return data['name'], data['function'], data['seats'] 20 | 21 | 22 | def load_data(): 23 | global decoded_data, jwgl_data 24 | if 'SLEEP_LIST' not in os.environ: 25 | raise Exception('SLEEP_LIST is not defined.') 26 | with open(os.environ['SLEEP_LIST'], mode='r', encoding='utf-8') as f: 27 | data = json.load(f) 28 | for k, v in data.items(): 29 | temp = {} 30 | for k_2, v_2 in v.items(): 31 | temp[k_2] = list(map(to_tuple, v_2)) 32 | decoded_data[k] = temp 33 | 34 | if 'JWGL_LIST' in os.environ: 35 | with open(os.environ['JWGL_LIST'], mode='r', encoding='utf-8') as f: 36 | data = json.load(f) 37 | for k, v in data.items(): 38 | temp = {} 39 | for k_2, v_2 in v.items(): 40 | temp[k_2] = list(map(to_tuple, v_2)) 41 | jwgl_data[k] = temp 42 | 43 | 44 | app = FastAPI() 45 | 46 | origins = [ 47 | "http://localhost:3000", 48 | "http://where-to-sleep.name1e5s.com", 49 | ] 50 | 51 | app.add_middleware( 52 | CORSMiddleware, 53 | allow_origins=origins, 54 | allow_credentials=True, 55 | allow_methods=["*"], 56 | allow_headers=["*"], 57 | ) 58 | 59 | app.add_event_handler("startup", load_data) 60 | 61 | 62 | def check_time(time) -> bool: 63 | if not time: 64 | return False 65 | for i in time: 66 | if i < 1 or i > 14: 67 | return False 68 | return True 69 | 70 | 71 | @app.get("/free_classrooms") 72 | async def read_item(week: int = 3, day: int = 1, time: List[int] = Query(None)): 73 | if week > 18 or week < 1 or day > 7 or day < 1 or not check_time(time): 74 | raise HTTPException( 75 | status_code=HTTP_404_NOT_FOUND, detail=f"Week {week}; day {day}; time {time} not found" 76 | ) 77 | data = merge_data(get_data(week, day, time)) 78 | return dict_to_list(data) 79 | 80 | 81 | @app.get("/free_classrooms_jwgl") 82 | async def read_item(week: int = 3, day: int = 1, time: List[int] = Query(None)): 83 | if week > 18 or week < 1 or day > 7 or day < 1 or not check_time(time): 84 | raise HTTPException( 85 | status_code=HTTP_404_NOT_FOUND, detail=f"Week {week}; day {day}; time {time} not found" 86 | ) 87 | data = merge_data(get_data_jwgl(week, day, time)) 88 | return dict_to_list(data) 89 | 90 | 91 | def get_data(week: int, day: int, time) -> List: 92 | week_str = '%02d' % week 93 | day_str = '%d' % (day - 1) 94 | result = [] 95 | for i in time: 96 | time_str = '%02d' % (i - 1) 97 | key = week_str + '.' + day_str + '.' + time_str 98 | result.append(decoded_data[key]) 99 | return result 100 | 101 | 102 | def get_data_jwgl(week: int, day: int, time) -> List: 103 | week_str = '%02d' % week 104 | day_str = '%d' % (day - 1) 105 | result = [] 106 | for i in time: 107 | time_str = '%02d' % (i - 1) 108 | key = week_str + '.' + day_str + '.' + time_str 109 | if key in jwgl_data: 110 | result.append(jwgl_data[key]) 111 | return result 112 | 113 | 114 | def merge_data(data): 115 | if len(data) == 0: 116 | return {} 117 | if len(data) == 1: 118 | return data[0] 119 | result = copy.deepcopy(data[0]) 120 | for i in range(1, len(data)): 121 | for j in result.keys(): 122 | if j not in data[i].keys(): 123 | result[j] = [] 124 | for k, v in data[i].items(): 125 | if k not in result.keys(): 126 | result[k] = [] 127 | else: 128 | temp = list(set(result[k]) & set(v)) 129 | result[k] = temp 130 | return result 131 | 132 | 133 | def dict_to_list(data): 134 | result = [] 135 | for k, v in data.items(): 136 | if len(v) > 0: 137 | v.sort(key=lambda x: x[0]) 138 | result.append({"building": k, "classrooms": list(map(lambda x: { 139 | 'name': x[0], 140 | 'function': x[1], 141 | 'seats': x[2]}, v))}) 142 | result.sort(key=lambda x: x['classrooms'][0]['name']) 143 | return result 144 | -------------------------------------------------------------------------------- /src/frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /src/frontend/README.md: -------------------------------------------------------------------------------- 1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 2 | 3 | ## Available Scripts 4 | 5 | In the project directory, you can run: 6 | 7 | ### `npm start` 8 | 9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 11 | 12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console. 14 | 15 | ### `npm test` 16 | 17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 19 | 20 | ### `npm run build` 21 | 22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance. 24 | 25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed! 27 | 28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 29 | 30 | ### `npm run eject` 31 | 32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 33 | 34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 35 | 36 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 37 | 38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 39 | 40 | ## Learn More 41 | 42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 43 | 44 | To learn React, check out the [React documentation](https://reactjs.org/). 45 | 46 | ### Code Splitting 47 | 48 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting 49 | 50 | ### Analyzing the Bundle Size 51 | 52 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size 53 | 54 | ### Making a Progressive Web App 55 | 56 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app 57 | 58 | ### Advanced Configuration 59 | 60 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration 61 | 62 | ### Deployment 63 | 64 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment 65 | 66 | ### `npm run build` fails to minify 67 | 68 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify 69 | -------------------------------------------------------------------------------- /src/frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "where-to-sleep", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^4.2.4", 7 | "@testing-library/react": "^9.5.0", 8 | "@testing-library/user-event": "^7.2.1", 9 | "bootstrap": "^4.5.2", 10 | "patch-package": "^6.4.7", 11 | "react": "^16.13.1", 12 | "react-dom": "^16.13.1", 13 | "react-scripts": "3.4.3", 14 | "shards-react": "^1.0.3" 15 | }, 16 | "scripts": { 17 | "start": "react-scripts start", 18 | "build": "react-scripts build", 19 | "test": "react-scripts test", 20 | "eject": "react-scripts eject", 21 | "postinstall": "patch-package" 22 | }, 23 | "eslintConfig": { 24 | "extends": "react-app" 25 | }, 26 | "browserslist": { 27 | "production": [ 28 | ">0.2%", 29 | "not dead", 30 | "not op_mini all" 31 | ], 32 | "development": [ 33 | "last 1 chrome version", 34 | "last 1 firefox version", 35 | "last 1 safari version" 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/name1e5s/WhereToSleep/47957029bda36b1747f2c8540b3f4432950ba79a/src/frontend/public/favicon.ico -------------------------------------------------------------------------------- /src/frontend/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 14 | 15 | 24 | 北京邮电大学西土城路校区空闲教室查询 25 | 26 | 27 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/frontend/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/name1e5s/WhereToSleep/47957029bda36b1747f2c8540b3f4432950ba79a/src/frontend/public/logo192.png -------------------------------------------------------------------------------- /src/frontend/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/name1e5s/WhereToSleep/47957029bda36b1747f2c8540b3f4432950ba79a/src/frontend/public/logo512.png -------------------------------------------------------------------------------- /src/frontend/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /src/frontend/public/rawdata_1.0.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": [ 3 | { 4 | "id": "0", 5 | "name": "安雅萍", 6 | "symbolSize": 19.12381, 7 | "x": -266.82776, 8 | "y": 299.6904, 9 | "value": 28.685715, 10 | "category": 0 11 | }, 12 | { 13 | "id": "1", 14 | "name": "白百合", 15 | "symbolSize": 2.6666666666666665, 16 | "x": -418.08344, 17 | "y": 446.8853, 18 | "value": 4, 19 | "category": 0 20 | }, 21 | { 22 | "id": "2", 23 | "name": "白冰", 24 | "symbolSize": 6.323809333333333, 25 | "x": -212.76357, 26 | "y": 245.29176, 27 | "value": 9.485714, 28 | "category": 1 29 | }, 30 | { 31 | "id": "3", 32 | "name": "陈钰琪", 33 | "symbolSize": 6.323809333333333, 34 | "x": -242.82404, 35 | "y": 235.26283, 36 | "value": 9.485714, 37 | "category": 1 38 | }, 39 | { 40 | "id": "4", 41 | "name": "陈冲", 42 | "symbolSize": 2.6666666666666665, 43 | "x": -379.30386, 44 | "y": 429.06424, 45 | "value": 4, 46 | "category": 0 47 | }, 48 | { 49 | "id": "5", 50 | "name": "陈红", 51 | "symbolSize": 2.6666666666666665, 52 | "x": -417.26337, 53 | "y": 406.03506, 54 | "value": 4, 55 | "category": 0 56 | }, 57 | { 58 | "id": "6", 59 | "name": "陈妍希", 60 | "symbolSize": 2.6666666666666665, 61 | "x": -332.6012, 62 | "y": 485.16974, 63 | "value": 4, 64 | "category": 0 65 | }, 66 | { 67 | "id": "7", 68 | "name": "陈意涵", 69 | "symbolSize": 2.6666666666666665, 70 | "x": -382.69568, 71 | "y": 475.09113, 72 | "value": 4, 73 | "category": 0 74 | }, 75 | { 76 | "id": "8", 77 | "name": "陈乔恩", 78 | "symbolSize": 2.6666666666666665, 79 | "x": -320.384, 80 | "y": 387.17325, 81 | "value": 4, 82 | "category": 0 83 | }, 84 | { 85 | "id": "9", 86 | "name": "陈紫涵", 87 | "symbolSize": 2.6666666666666665, 88 | "x": -344.39832, 89 | "y": 451.16772, 90 | "value": 4, 91 | "category": 0 92 | }, 93 | { 94 | "id": "10", 95 | "name": "楚月", 96 | "symbolSize": 2.6666666666666665, 97 | "x": -89.34107, 98 | "y": 234.56128, 99 | "value": 4, 100 | "category": 1 101 | }, 102 | { 103 | "id": "11", 104 | "name": "程愫", 105 | "symbolSize": 66.66666666666667, 106 | "x": -87.93029, 107 | "y": -6.8120565, 108 | "value": 100, 109 | "category": 1 110 | }, 111 | { 112 | "id": "12", 113 | "name": "蔡依林", 114 | "symbolSize": 4.495239333333333, 115 | "x": -339.77908, 116 | "y": -184.69139, 117 | "value": 6.742859, 118 | "category": 1 119 | }, 120 | { 121 | "id": "13", 122 | "name": "陈数", 123 | "symbolSize": 2.6666666666666665, 124 | "x": -194.31313, 125 | "y": 178.55301, 126 | "value": 4, 127 | "category": 1 128 | }, 129 | { 130 | "id": "14", 131 | "name": "蔡少芬", 132 | "symbolSize": 2.6666666666666665, 133 | "x": -158.05168, 134 | "y": 201.99768, 135 | "value": 4, 136 | "category": 1 137 | }, 138 | { 139 | "id": "15", 140 | "name": "陈美琪", 141 | "symbolSize": 2.6666666666666665, 142 | "x": -127.701546, 143 | "y": 242.55057, 144 | "value": 4, 145 | "category": 1 146 | }, 147 | { 148 | "id": "16", 149 | "name": "陈晓旭", 150 | "symbolSize": 17.295237333333333, 151 | "x": -385.2226, 152 | "y": -393.5572, 153 | "value": 25.942856, 154 | "category": 2 155 | }, 156 | { 157 | "id": "17", 158 | "name": "陈瑶", 159 | "symbolSize": 13.638097333333334, 160 | "x": -516.55884, 161 | "y": -393.98975, 162 | "value": 20.457146, 163 | "category": 2 164 | }, 165 | { 166 | "id": "18", 167 | "name": "程瑷瑗", 168 | "symbolSize": 13.638097333333334, 169 | "x": -464.79382, 170 | "y": -493.57944, 171 | "value": 20.457146, 172 | "category": 2 173 | }, 174 | { 175 | "id": "19", 176 | "name": "迪丽热巴", 177 | "symbolSize": 13.638097333333334, 178 | "x": -515.1624, 179 | "y": -456.9891, 180 | "value": 20.457146, 181 | "category": 2 182 | }, 183 | { 184 | "id": "20", 185 | "name": "邓家佳", 186 | "symbolSize": 13.638097333333334, 187 | "x": -408.12122, 188 | "y": -464.5048, 189 | "value": 20.457146, 190 | "category": 2 191 | }, 192 | { 193 | "id": "21", 194 | "name": "董洁", 195 | "symbolSize": 13.638097333333334, 196 | "x": -456.44113, 197 | "y": -425.13303, 198 | "value": 20.457146, 199 | "category": 2 200 | }, 201 | { 202 | "id": "22", 203 | "name": "杜若溪", 204 | "symbolSize": 13.638097333333334, 205 | "x": -459.1107, 206 | "y": -362.5133, 207 | "value": 20.457146, 208 | "category": 2 209 | }, 210 | { 211 | "id": "23", 212 | "name": "范冰冰", 213 | "symbolSize": 28.266666666666666, 214 | "x": -313.42786, 215 | "y": -289.44803, 216 | "value": 42.4, 217 | "category": 2 218 | }, 219 | { 220 | "id": "24", 221 | "name": "付梦妮", 222 | "symbolSize": 20.95238266666667, 223 | "x": 4.6313396, 224 | "y": -273.8517, 225 | "value": 31.428574, 226 | "category": 7 227 | }, 228 | { 229 | "id": "25", 230 | "name": "范文芳", 231 | "symbolSize": 30.095235333333335, 232 | "x": 82.80825, 233 | "y": -203.1144, 234 | "value": 45.142853, 235 | "category": 7 236 | }, 237 | { 238 | "id": "26", 239 | "name": "巩俐", 240 | "symbolSize": 20.95238266666667, 241 | "x": 78.64646, 242 | "y": -31.512747, 243 | "value": 31.428574, 244 | "category": 6 245 | }, 246 | { 247 | "id": "27", 248 | "name": "郭采洁", 249 | "symbolSize": 31.923806666666668, 250 | "x": -81.46074, 251 | "y": -204.20204, 252 | "value": 47.88571, 253 | "category": 7 254 | }, 255 | { 256 | "id": "28", 257 | "name": "郭碧婷", 258 | "symbolSize": 8.152382000000001, 259 | "x": -225.73984, 260 | "y": 82.41631, 261 | "value": 12.228573, 262 | "category": 4 263 | }, 264 | { 265 | "id": "29", 266 | "name": "关之琳", 267 | "symbolSize": 15.466666666666667, 268 | "x": -385.6842, 269 | "y": -20.206686, 270 | "value": 23.2, 271 | "category": 3 272 | }, 273 | { 274 | "id": "30", 275 | "name": "高圆圆", 276 | "symbolSize": 4.495239333333333, 277 | "x": -403.92447, 278 | "y": -197.69823, 279 | "value": 6.742859, 280 | "category": 2 281 | }, 282 | { 283 | "id": "31", 284 | "name": "郭雪芙", 285 | "symbolSize": 8.152382000000001, 286 | "x": -281.4253, 287 | "y": -158.45137, 288 | "value": 12.228573, 289 | "category": 2 290 | }, 291 | { 292 | "id": "32", 293 | "name": "盖丽丽", 294 | "symbolSize": 2.6666666666666665, 295 | "x": -122.41348, 296 | "y": 210.37503, 297 | "value": 4, 298 | "category": 1 299 | }, 300 | { 301 | "id": "33", 302 | "name": "高晓菲", 303 | "symbolSize": 4.495239333333333, 304 | "x": -234.6001, 305 | "y": -113.15067, 306 | "value": 6.742859, 307 | "category": 1 308 | }, 309 | { 310 | "id": "34", 311 | "name": "高露", 312 | "symbolSize": 11.809524666666666, 313 | "x": -387.84915, 314 | "y": 58.7059, 315 | "value": 17.714287, 316 | "category": 3 317 | }, 318 | { 319 | "id": "35", 320 | "name": "郭珍霓", 321 | "symbolSize": 11.809524666666666, 322 | "x": -338.2307, 323 | "y": 87.48405, 324 | "value": 17.714287, 325 | "category": 3 326 | }, 327 | { 328 | "id": "36", 329 | "name": "高洋", 330 | "symbolSize": 11.809524666666666, 331 | "x": -453.26874, 332 | "y": 58.94648, 333 | "value": 17.714287, 334 | "category": 3 335 | }, 336 | { 337 | "id": "37", 338 | "name": "甘婷婷", 339 | "symbolSize": 11.809524666666666, 340 | "x": -386.44904, 341 | "y": 140.05937, 342 | "value": 17.714287, 343 | "category": 3 344 | }, 345 | { 346 | "id": "38", 347 | "name": "韩红", 348 | "symbolSize": 11.809524666666666, 349 | "x": -446.7876, 350 | "y": 123.38005, 351 | "value": 17.714287, 352 | "category": 3 353 | }, 354 | { 355 | "id": "39", 356 | "name": "黄圣依", 357 | "symbolSize": 6.323809333333333, 358 | "x": 336.49738, 359 | "y": -269.55914, 360 | "value": 9.485714, 361 | "category": 6 362 | }, 363 | { 364 | "id": "40", 365 | "name": "何穂", 366 | "symbolSize": 2.6666666666666665, 367 | "x": 29.187843, 368 | "y": -460.13132, 369 | "value": 4, 370 | "category": 7 371 | }, 372 | { 373 | "id": "41", 374 | "name": "何泓珊", 375 | "symbolSize": 20.95238266666667, 376 | "x": 238.36697, 377 | "y": -210.00926, 378 | "value": 31.428574, 379 | "category": 7 380 | }, 381 | { 382 | "id": "42", 383 | "name": "何曼婷", 384 | "symbolSize": 6.323809333333333, 385 | "x": 189.69513, 386 | "y": -346.50662, 387 | "value": 9.485714, 388 | "category": 7 389 | }, 390 | { 391 | "id": "43", 392 | "name": "韩雪", 393 | "symbolSize": 6.323809333333333, 394 | "x": -187.00418, 395 | "y": -145.02663, 396 | "value": 9.485714, 397 | "category": 6 398 | }, 399 | { 400 | "id": "44", 401 | "name": "韩瑜", 402 | "symbolSize": 4.495239333333333, 403 | "x": -252.99521, 404 | "y": 129.87549, 405 | "value": 6.742859, 406 | "category": 4 407 | }, 408 | { 409 | "id": "45", 410 | "name": "何琢言", 411 | "symbolSize": 2.6666666666666665, 412 | "x": -296.07935, 413 | "y": 163.11964, 414 | "value": 4, 415 | "category": 4 416 | }, 417 | { 418 | "id": "46", 419 | "name": "景甜", 420 | "symbolSize": 2.6666666666666665, 421 | "x": 550.3201, 422 | "y": 522.4031, 423 | "value": 4, 424 | "category": 5 425 | }, 426 | { 427 | "id": "47", 428 | "name": "江疏影", 429 | "symbolSize": 4.495239333333333, 430 | "x": 488.13535, 431 | "y": 356.8573, 432 | "value": 6.742859, 433 | "category": 5 434 | }, 435 | { 436 | "id": "48", 437 | "name": "蒋欣", 438 | "symbolSize": 41.06667066666667, 439 | "x": 387.89572, 440 | "y": 110.462326, 441 | "value": 61.600006, 442 | "category": 8 443 | }, 444 | { 445 | "id": "49", 446 | "name": "蒋依依", 447 | "symbolSize": 13.638097333333334, 448 | "x": 126.4831, 449 | "y": 68.10622, 450 | "value": 20.457146, 451 | "category": 6 452 | }, 453 | { 454 | "id": "50", 455 | "name": "金莎", 456 | "symbolSize": 4.495239333333333, 457 | "x": 127.07365, 458 | "y": -113.05923, 459 | "value": 6.742859, 460 | "category": 6 461 | }, 462 | { 463 | "id": "51", 464 | "name": "昆凌", 465 | "symbolSize": 13.638097333333334, 466 | "x": 162.63559, 467 | "y": 117.6565, 468 | "value": 20.457146, 469 | "category": 6 470 | }, 471 | { 472 | "id": "52", 473 | "name": "李冰冰", 474 | "symbolSize": 4.495239333333333, 475 | "x": 353.66415, 476 | "y": -205.89165, 477 | "value": 6.742859, 478 | "category": 6 479 | }, 480 | { 481 | "id": "53", 482 | "name": "刘诗诗", 483 | "symbolSize": 2.6666666666666665, 484 | "x": 165.43939, 485 | "y": 339.7736, 486 | "value": 4, 487 | "category": 6 488 | }, 489 | { 490 | "id": "54", 491 | "name": "刘雯", 492 | "symbolSize": 8.152382000000001, 493 | "x": 137.69348, 494 | "y": 196.1069, 495 | "value": 12.228573, 496 | "category": 6 497 | }, 498 | { 499 | "id": "55", 500 | "name": "刘亦菲", 501 | "symbolSize": 35.58095333333333, 502 | "x": 206.44687, 503 | "y": -13.805411, 504 | "value": 53.37143, 505 | "category": 6 506 | }, 507 | { 508 | "id": "56", 509 | "name": "林心如", 510 | "symbolSize": 4.495239333333333, 511 | "x": 194.82993, 512 | "y": 224.78036, 513 | "value": 6.742859, 514 | "category": 6 515 | }, 516 | { 517 | "id": "57", 518 | "name": "林志玲", 519 | "symbolSize": 20.95238266666667, 520 | "x": 597.6618, 521 | "y": 135.18481, 522 | "value": 31.428574, 523 | "category": 8 524 | }, 525 | { 526 | "id": "58", 527 | "name": "李湘", 528 | "symbolSize": 28.266666666666666, 529 | "x": 355.78366, 530 | "y": -74.882454, 531 | "value": 42.4, 532 | "category": 8 533 | }, 534 | { 535 | "id": "59", 536 | "name": "李亚男", 537 | "symbolSize": 20.95238266666667, 538 | "x": 515.2961, 539 | "y": -46.167564, 540 | "value": 31.428574, 541 | "category": 8 542 | }, 543 | { 544 | "id": "60", 545 | "name": "李若彤", 546 | "symbolSize": 17.295237333333333, 547 | "x": 614.29285, 548 | "y": -69.3104, 549 | "value": 25.942856, 550 | "category": 8 551 | }, 552 | { 553 | "id": "61", 554 | "name": "李沁", 555 | "symbolSize": 20.95238266666667, 556 | "x": 550.1917, 557 | "y": -128.17537, 558 | "value": 31.428574, 559 | "category": 8 560 | }, 561 | { 562 | "id": "62", 563 | "name": "林依晨", 564 | "symbolSize": 24.609526666666667, 565 | "x": 436.17184, 566 | "y": -12.7286825, 567 | "value": 36.91429, 568 | "category": 8 569 | }, 570 | { 571 | "id": "63", 572 | "name": "刘嘉玲", 573 | "symbolSize": 22.780953333333333, 574 | "x": 602.55225, 575 | "y": 16.421427, 576 | "value": 34.17143, 577 | "category": 8 578 | }, 579 | { 580 | "id": "64", 581 | "name": "闰妮", 582 | "symbolSize": 24.609526666666667, 583 | "x": 455.81955, 584 | "y": -115.45826, 585 | "value": 36.91429, 586 | "category": 8 587 | }, 588 | { 589 | "id": "65", 590 | "name": "李宇春", 591 | "symbolSize": 22.780953333333333, 592 | "x": 516.40784, 593 | "y": 47.242233, 594 | "value": 34.17143, 595 | "category": 8 596 | }, 597 | { 598 | "id": "66", 599 | "name": "李晟", 600 | "symbolSize": 19.12381, 601 | "x": 646.4313, 602 | "y": -151.06331, 603 | "value": 28.685715, 604 | "category": 8 605 | }, 606 | { 607 | "id": "67", 608 | "name": "罗震环", 609 | "symbolSize": 2.6666666666666665, 610 | "x": 668.9568, 611 | "y": 204.65488, 612 | "value": 4, 613 | "category": 8 614 | }, 615 | { 616 | "id": "68", 617 | "name": "刘雨欣", 618 | "symbolSize": 19.12381, 619 | "x": 78.4799, 620 | "y": -347.15146, 621 | "value": 28.685715, 622 | "category": 7 623 | }, 624 | { 625 | "id": "69", 626 | "name": "李波儿", 627 | "symbolSize": 19.12381, 628 | "x": 150.35959, 629 | "y": -298.50797, 630 | "value": 28.685715, 631 | "category": 7 632 | }, 633 | { 634 | "id": "70", 635 | "name": "黎姿", 636 | "symbolSize": 19.12381, 637 | "x": 137.3717, 638 | "y": -410.2809, 639 | "value": 28.685715, 640 | "category": 7 641 | }, 642 | { 643 | "id": "71", 644 | "name": "张敏", 645 | "symbolSize": 17.295237333333333, 646 | "x": 234.87747, 647 | "y": -400.85983, 648 | "value": 25.942856, 649 | "category": 7 650 | }, 651 | { 652 | "id": "72", 653 | "name": "梁小冰", 654 | "symbolSize": 6.323809333333333, 655 | "x": 40.942253, 656 | "y": 113.78272, 657 | "value": 9.485714, 658 | "category": 1 659 | }, 660 | { 661 | "id": "73", 662 | "name": "黎美娴", 663 | "symbolSize": 4.495239333333333, 664 | "x": 437.939, 665 | "y": 291.58234, 666 | "value": 6.742859, 667 | "category": 8 668 | }, 669 | { 670 | "id": "74", 671 | "name": "林允儿", 672 | "symbolSize": 4.495239333333333, 673 | "x": 466.04922, 674 | "y": 283.3606, 675 | "value": 6.742859, 676 | "category": 8 677 | }, 678 | { 679 | "id": "75", 680 | "name": "米雪", 681 | "symbolSize": 13.638097333333334, 682 | "x": 238.79364, 683 | "y": -314.06345, 684 | "value": 20.457146, 685 | "category": 7 686 | }, 687 | { 688 | "id": "76", 689 | "name": "娄艺潇", 690 | "symbolSize": 13.638097333333334, 691 | "x": 712.18353, 692 | "y": 4.8131495, 693 | "value": 20.457146, 694 | "category": 8 695 | } 696 | ], 697 | "links": [ 698 | { 699 | "source": "1", 700 | "target": "0" 701 | }, 702 | { 703 | "source": "2", 704 | "target": "0" 705 | }, 706 | { 707 | "source": "3", 708 | "target": "0" 709 | }, 710 | { 711 | "source": "3", 712 | "target": "2" 713 | }, 714 | { 715 | "source": "4", 716 | "target": "0" 717 | }, 718 | { 719 | "source": "5", 720 | "target": "0" 721 | }, 722 | { 723 | "source": "6", 724 | "target": "0" 725 | }, 726 | { 727 | "source": "7", 728 | "target": "0" 729 | }, 730 | { 731 | "source": "8", 732 | "target": "0" 733 | }, 734 | { 735 | "source": "9", 736 | "target": "0" 737 | }, 738 | { 739 | "source": "11", 740 | "target": "0" 741 | }, 742 | { 743 | "source": "11", 744 | "target": "2" 745 | }, 746 | { 747 | "source": "11", 748 | "target": "3" 749 | }, 750 | { 751 | "source": "11", 752 | "target": "10" 753 | }, 754 | { 755 | "source": "12", 756 | "target": "11" 757 | }, 758 | { 759 | "source": "13", 760 | "target": "11" 761 | }, 762 | { 763 | "source": "14", 764 | "target": "11" 765 | }, 766 | { 767 | "source": "15", 768 | "target": "11" 769 | }, 770 | { 771 | "source": "17", 772 | "target": "16" 773 | }, 774 | { 775 | "source": "18", 776 | "target": "16" 777 | }, 778 | { 779 | "source": "18", 780 | "target": "17" 781 | }, 782 | { 783 | "source": "19", 784 | "target": "16" 785 | }, 786 | { 787 | "source": "19", 788 | "target": "17" 789 | }, 790 | { 791 | "source": "19", 792 | "target": "18" 793 | }, 794 | { 795 | "source": "20", 796 | "target": "16" 797 | }, 798 | { 799 | "source": "20", 800 | "target": "17" 801 | }, 802 | { 803 | "source": "20", 804 | "target": "18" 805 | }, 806 | { 807 | "source": "20", 808 | "target": "19" 809 | }, 810 | { 811 | "source": "21", 812 | "target": "16" 813 | }, 814 | { 815 | "source": "21", 816 | "target": "17" 817 | }, 818 | { 819 | "source": "21", 820 | "target": "18" 821 | }, 822 | { 823 | "source": "21", 824 | "target": "19" 825 | }, 826 | { 827 | "source": "21", 828 | "target": "20" 829 | }, 830 | { 831 | "source": "22", 832 | "target": "16" 833 | }, 834 | { 835 | "source": "22", 836 | "target": "17" 837 | }, 838 | { 839 | "source": "22", 840 | "target": "18" 841 | }, 842 | { 843 | "source": "22", 844 | "target": "19" 845 | }, 846 | { 847 | "source": "22", 848 | "target": "20" 849 | }, 850 | { 851 | "source": "22", 852 | "target": "21" 853 | }, 854 | { 855 | "source": "23", 856 | "target": "11" 857 | }, 858 | { 859 | "source": "23", 860 | "target": "12" 861 | }, 862 | { 863 | "source": "23", 864 | "target": "16" 865 | }, 866 | { 867 | "source": "23", 868 | "target": "17" 869 | }, 870 | { 871 | "source": "23", 872 | "target": "18" 873 | }, 874 | { 875 | "source": "23", 876 | "target": "19" 877 | }, 878 | { 879 | "source": "23", 880 | "target": "20" 881 | }, 882 | { 883 | "source": "23", 884 | "target": "21" 885 | }, 886 | { 887 | "source": "23", 888 | "target": "22" 889 | }, 890 | { 891 | "source": "24", 892 | "target": "11" 893 | }, 894 | { 895 | "source": "24", 896 | "target": "23" 897 | }, 898 | { 899 | "source": "25", 900 | "target": "11" 901 | }, 902 | { 903 | "source": "25", 904 | "target": "23" 905 | }, 906 | { 907 | "source": "25", 908 | "target": "24" 909 | }, 910 | { 911 | "source": "26", 912 | "target": "11" 913 | }, 914 | { 915 | "source": "26", 916 | "target": "16" 917 | }, 918 | { 919 | "source": "26", 920 | "target": "24" 921 | }, 922 | { 923 | "source": "26", 924 | "target": "25" 925 | }, 926 | { 927 | "source": "27", 928 | "target": "11" 929 | }, 930 | { 931 | "source": "27", 932 | "target": "23" 933 | }, 934 | { 935 | "source": "27", 936 | "target": "24" 937 | }, 938 | { 939 | "source": "27", 940 | "target": "25" 941 | }, 942 | { 943 | "source": "27", 944 | "target": "26" 945 | }, 946 | { 947 | "source": "28", 948 | "target": "11" 949 | }, 950 | { 951 | "source": "28", 952 | "target": "27" 953 | }, 954 | { 955 | "source": "29", 956 | "target": "11" 957 | }, 958 | { 959 | "source": "29", 960 | "target": "23" 961 | }, 962 | { 963 | "source": "29", 964 | "target": "27" 965 | }, 966 | { 967 | "source": "30", 968 | "target": "23" 969 | }, 970 | { 971 | "source": "31", 972 | "target": "11" 973 | }, 974 | { 975 | "source": "31", 976 | "target": "23" 977 | }, 978 | { 979 | "source": "31", 980 | "target": "27" 981 | }, 982 | { 983 | "source": "31", 984 | "target": "30" 985 | }, 986 | { 987 | "source": "32", 988 | "target": "11" 989 | }, 990 | { 991 | "source": "33", 992 | "target": "11" 993 | }, 994 | { 995 | "source": "33", 996 | "target": "27" 997 | }, 998 | { 999 | "source": "34", 1000 | "target": "11" 1001 | }, 1002 | { 1003 | "source": "34", 1004 | "target": "29" 1005 | }, 1006 | { 1007 | "source": "35", 1008 | "target": "11" 1009 | }, 1010 | { 1011 | "source": "35", 1012 | "target": "29" 1013 | }, 1014 | { 1015 | "source": "35", 1016 | "target": "34" 1017 | }, 1018 | { 1019 | "source": "36", 1020 | "target": "11" 1021 | }, 1022 | { 1023 | "source": "36", 1024 | "target": "29" 1025 | }, 1026 | { 1027 | "source": "36", 1028 | "target": "34" 1029 | }, 1030 | { 1031 | "source": "36", 1032 | "target": "35" 1033 | }, 1034 | { 1035 | "source": "37", 1036 | "target": "11" 1037 | }, 1038 | { 1039 | "source": "37", 1040 | "target": "29" 1041 | }, 1042 | { 1043 | "source": "37", 1044 | "target": "34" 1045 | }, 1046 | { 1047 | "source": "37", 1048 | "target": "35" 1049 | }, 1050 | { 1051 | "source": "37", 1052 | "target": "36" 1053 | }, 1054 | { 1055 | "source": "38", 1056 | "target": "11" 1057 | }, 1058 | { 1059 | "source": "38", 1060 | "target": "29" 1061 | }, 1062 | { 1063 | "source": "38", 1064 | "target": "34" 1065 | }, 1066 | { 1067 | "source": "38", 1068 | "target": "35" 1069 | }, 1070 | { 1071 | "source": "38", 1072 | "target": "36" 1073 | }, 1074 | { 1075 | "source": "38", 1076 | "target": "37" 1077 | }, 1078 | { 1079 | "source": "39", 1080 | "target": "25" 1081 | }, 1082 | { 1083 | "source": "40", 1084 | "target": "25" 1085 | }, 1086 | { 1087 | "source": "41", 1088 | "target": "24" 1089 | }, 1090 | { 1091 | "source": "41", 1092 | "target": "25" 1093 | }, 1094 | { 1095 | "source": "42", 1096 | "target": "24" 1097 | }, 1098 | { 1099 | "source": "42", 1100 | "target": "25" 1101 | }, 1102 | { 1103 | "source": "42", 1104 | "target": "41" 1105 | }, 1106 | { 1107 | "source": "43", 1108 | "target": "11" 1109 | }, 1110 | { 1111 | "source": "43", 1112 | "target": "26" 1113 | }, 1114 | { 1115 | "source": "43", 1116 | "target": "27" 1117 | }, 1118 | { 1119 | "source": "44", 1120 | "target": "11" 1121 | }, 1122 | { 1123 | "source": "44", 1124 | "target": "28" 1125 | }, 1126 | { 1127 | "source": "45", 1128 | "target": "28" 1129 | }, 1130 | { 1131 | "source": "47", 1132 | "target": "46" 1133 | }, 1134 | { 1135 | "source": "48", 1136 | "target": "11" 1137 | }, 1138 | { 1139 | "source": "48", 1140 | "target": "25" 1141 | }, 1142 | { 1143 | "source": "48", 1144 | "target": "27" 1145 | }, 1146 | { 1147 | "source": "48", 1148 | "target": "47" 1149 | }, 1150 | { 1151 | "source": "49", 1152 | "target": "11" 1153 | }, 1154 | { 1155 | "source": "49", 1156 | "target": "26" 1157 | }, 1158 | { 1159 | "source": "50", 1160 | "target": "24" 1161 | }, 1162 | { 1163 | "source": "50", 1164 | "target": "49" 1165 | }, 1166 | { 1167 | "source": "51", 1168 | "target": "11" 1169 | }, 1170 | { 1171 | "source": "51", 1172 | "target": "26" 1173 | }, 1174 | { 1175 | "source": "51", 1176 | "target": "49" 1177 | }, 1178 | { 1179 | "source": "52", 1180 | "target": "39" 1181 | }, 1182 | { 1183 | "source": "52", 1184 | "target": "51" 1185 | }, 1186 | { 1187 | "source": "53", 1188 | "target": "51" 1189 | }, 1190 | { 1191 | "source": "54", 1192 | "target": "26" 1193 | }, 1194 | { 1195 | "source": "54", 1196 | "target": "49" 1197 | }, 1198 | { 1199 | "source": "54", 1200 | "target": "51" 1201 | }, 1202 | { 1203 | "source": "55", 1204 | "target": "11" 1205 | }, 1206 | { 1207 | "source": "55", 1208 | "target": "16" 1209 | }, 1210 | { 1211 | "source": "55", 1212 | "target": "25" 1213 | }, 1214 | { 1215 | "source": "55", 1216 | "target": "26" 1217 | }, 1218 | { 1219 | "source": "55", 1220 | "target": "39" 1221 | }, 1222 | { 1223 | "source": "55", 1224 | "target": "41" 1225 | }, 1226 | { 1227 | "source": "55", 1228 | "target": "48" 1229 | }, 1230 | { 1231 | "source": "55", 1232 | "target": "49" 1233 | }, 1234 | { 1235 | "source": "55", 1236 | "target": "51" 1237 | }, 1238 | { 1239 | "source": "55", 1240 | "target": "54" 1241 | }, 1242 | { 1243 | "source": "56", 1244 | "target": "49" 1245 | }, 1246 | { 1247 | "source": "56", 1248 | "target": "55" 1249 | }, 1250 | { 1251 | "source": "57", 1252 | "target": "41" 1253 | }, 1254 | { 1255 | "source": "57", 1256 | "target": "48" 1257 | }, 1258 | { 1259 | "source": "57", 1260 | "target": "55" 1261 | }, 1262 | { 1263 | "source": "58", 1264 | "target": "11" 1265 | }, 1266 | { 1267 | "source": "58", 1268 | "target": "27" 1269 | }, 1270 | { 1271 | "source": "58", 1272 | "target": "48" 1273 | }, 1274 | { 1275 | "source": "58", 1276 | "target": "55" 1277 | }, 1278 | { 1279 | "source": "58", 1280 | "target": "57" 1281 | }, 1282 | { 1283 | "source": "59", 1284 | "target": "48" 1285 | }, 1286 | { 1287 | "source": "59", 1288 | "target": "55" 1289 | }, 1290 | { 1291 | "source": "59", 1292 | "target": "57" 1293 | }, 1294 | { 1295 | "source": "59", 1296 | "target": "58" 1297 | }, 1298 | { 1299 | "source": "60", 1300 | "target": "48" 1301 | }, 1302 | { 1303 | "source": "60", 1304 | "target": "58" 1305 | }, 1306 | { 1307 | "source": "60", 1308 | "target": "59" 1309 | }, 1310 | { 1311 | "source": "61", 1312 | "target": "48" 1313 | }, 1314 | { 1315 | "source": "61", 1316 | "target": "55" 1317 | }, 1318 | { 1319 | "source": "61", 1320 | "target": "57" 1321 | }, 1322 | { 1323 | "source": "61", 1324 | "target": "58" 1325 | }, 1326 | { 1327 | "source": "61", 1328 | "target": "59" 1329 | }, 1330 | { 1331 | "source": "61", 1332 | "target": "60" 1333 | }, 1334 | { 1335 | "source": "62", 1336 | "target": "41" 1337 | }, 1338 | { 1339 | "source": "62", 1340 | "target": "48" 1341 | }, 1342 | { 1343 | "source": "62", 1344 | "target": "55" 1345 | }, 1346 | { 1347 | "source": "62", 1348 | "target": "57" 1349 | }, 1350 | { 1351 | "source": "62", 1352 | "target": "58" 1353 | }, 1354 | { 1355 | "source": "62", 1356 | "target": "59" 1357 | }, 1358 | { 1359 | "source": "62", 1360 | "target": "60" 1361 | }, 1362 | { 1363 | "source": "62", 1364 | "target": "61" 1365 | }, 1366 | { 1367 | "source": "63", 1368 | "target": "48" 1369 | }, 1370 | { 1371 | "source": "63", 1372 | "target": "55" 1373 | }, 1374 | { 1375 | "source": "63", 1376 | "target": "57" 1377 | }, 1378 | { 1379 | "source": "63", 1380 | "target": "58" 1381 | }, 1382 | { 1383 | "source": "63", 1384 | "target": "59" 1385 | }, 1386 | { 1387 | "source": "63", 1388 | "target": "60" 1389 | }, 1390 | { 1391 | "source": "63", 1392 | "target": "61" 1393 | }, 1394 | { 1395 | "source": "63", 1396 | "target": "62" 1397 | }, 1398 | { 1399 | "source": "64", 1400 | "target": "11" 1401 | }, 1402 | { 1403 | "source": "64", 1404 | "target": "48" 1405 | }, 1406 | { 1407 | "source": "64", 1408 | "target": "55" 1409 | }, 1410 | { 1411 | "source": "64", 1412 | "target": "57" 1413 | }, 1414 | { 1415 | "source": "64", 1416 | "target": "58" 1417 | }, 1418 | { 1419 | "source": "64", 1420 | "target": "59" 1421 | }, 1422 | { 1423 | "source": "64", 1424 | "target": "60" 1425 | }, 1426 | { 1427 | "source": "64", 1428 | "target": "61" 1429 | }, 1430 | { 1431 | "source": "64", 1432 | "target": "62" 1433 | }, 1434 | { 1435 | "source": "64", 1436 | "target": "63" 1437 | }, 1438 | { 1439 | "source": "65", 1440 | "target": "48" 1441 | }, 1442 | { 1443 | "source": "65", 1444 | "target": "55" 1445 | }, 1446 | { 1447 | "source": "65", 1448 | "target": "57" 1449 | }, 1450 | { 1451 | "source": "65", 1452 | "target": "58" 1453 | }, 1454 | { 1455 | "source": "65", 1456 | "target": "59" 1457 | }, 1458 | { 1459 | "source": "65", 1460 | "target": "60" 1461 | }, 1462 | { 1463 | "source": "65", 1464 | "target": "61" 1465 | }, 1466 | { 1467 | "source": "65", 1468 | "target": "62" 1469 | }, 1470 | { 1471 | "source": "65", 1472 | "target": "63" 1473 | }, 1474 | { 1475 | "source": "65", 1476 | "target": "64" 1477 | }, 1478 | { 1479 | "source": "66", 1480 | "target": "48" 1481 | }, 1482 | { 1483 | "source": "66", 1484 | "target": "58" 1485 | }, 1486 | { 1487 | "source": "66", 1488 | "target": "59" 1489 | }, 1490 | { 1491 | "source": "66", 1492 | "target": "60" 1493 | }, 1494 | { 1495 | "source": "66", 1496 | "target": "61" 1497 | }, 1498 | { 1499 | "source": "66", 1500 | "target": "62" 1501 | }, 1502 | { 1503 | "source": "66", 1504 | "target": "63" 1505 | }, 1506 | { 1507 | "source": "66", 1508 | "target": "64" 1509 | }, 1510 | { 1511 | "source": "66", 1512 | "target": "65" 1513 | }, 1514 | { 1515 | "source": "67", 1516 | "target": "57" 1517 | }, 1518 | { 1519 | "source": "68", 1520 | "target": "11" 1521 | }, 1522 | { 1523 | "source": "68", 1524 | "target": "24" 1525 | }, 1526 | { 1527 | "source": "68", 1528 | "target": "25" 1529 | }, 1530 | { 1531 | "source": "68", 1532 | "target": "27" 1533 | }, 1534 | { 1535 | "source": "68", 1536 | "target": "41" 1537 | }, 1538 | { 1539 | "source": "68", 1540 | "target": "48" 1541 | }, 1542 | { 1543 | "source": "69", 1544 | "target": "11" 1545 | }, 1546 | { 1547 | "source": "69", 1548 | "target": "24" 1549 | }, 1550 | { 1551 | "source": "69", 1552 | "target": "25" 1553 | }, 1554 | { 1555 | "source": "69", 1556 | "target": "27" 1557 | }, 1558 | { 1559 | "source": "69", 1560 | "target": "41" 1561 | }, 1562 | { 1563 | "source": "69", 1564 | "target": "48" 1565 | }, 1566 | { 1567 | "source": "69", 1568 | "target": "68" 1569 | }, 1570 | { 1571 | "source": "70", 1572 | "target": "11" 1573 | }, 1574 | { 1575 | "source": "70", 1576 | "target": "24" 1577 | }, 1578 | { 1579 | "source": "70", 1580 | "target": "25" 1581 | }, 1582 | { 1583 | "source": "70", 1584 | "target": "27" 1585 | }, 1586 | { 1587 | "source": "70", 1588 | "target": "41" 1589 | }, 1590 | { 1591 | "source": "70", 1592 | "target": "58" 1593 | }, 1594 | { 1595 | "source": "70", 1596 | "target": "68" 1597 | }, 1598 | { 1599 | "source": "70", 1600 | "target": "69" 1601 | }, 1602 | { 1603 | "source": "71", 1604 | "target": "11" 1605 | }, 1606 | { 1607 | "source": "71", 1608 | "target": "25" 1609 | }, 1610 | { 1611 | "source": "71", 1612 | "target": "27" 1613 | }, 1614 | { 1615 | "source": "71", 1616 | "target": "41" 1617 | }, 1618 | { 1619 | "source": "71", 1620 | "target": "48" 1621 | }, 1622 | { 1623 | "source": "71", 1624 | "target": "68" 1625 | }, 1626 | { 1627 | "source": "71", 1628 | "target": "69" 1629 | }, 1630 | { 1631 | "source": "71", 1632 | "target": "70" 1633 | }, 1634 | { 1635 | "source": "72", 1636 | "target": "11" 1637 | }, 1638 | { 1639 | "source": "72", 1640 | "target": "26" 1641 | }, 1642 | { 1643 | "source": "72", 1644 | "target": "27" 1645 | }, 1646 | { 1647 | "source": "73", 1648 | "target": "48" 1649 | }, 1650 | { 1651 | "source": "74", 1652 | "target": "48" 1653 | }, 1654 | { 1655 | "source": "74", 1656 | "target": "73" 1657 | }, 1658 | { 1659 | "source": "75", 1660 | "target": "25" 1661 | }, 1662 | { 1663 | "source": "75", 1664 | "target": "41" 1665 | }, 1666 | { 1667 | "source": "75", 1668 | "target": "48" 1669 | }, 1670 | { 1671 | "source": "75", 1672 | "target": "68" 1673 | }, 1674 | { 1675 | "source": "75", 1676 | "target": "69" 1677 | }, 1678 | { 1679 | "source": "75", 1680 | "target": "70" 1681 | }, 1682 | { 1683 | "source": "75", 1684 | "target": "71" 1685 | }, 1686 | { 1687 | "source": "76", 1688 | "target": "48" 1689 | }, 1690 | { 1691 | "source": "76", 1692 | "target": "58" 1693 | }, 1694 | { 1695 | "source": "76", 1696 | "target": "62" 1697 | }, 1698 | { 1699 | "source": "76", 1700 | "target": "63" 1701 | }, 1702 | { 1703 | "source": "76", 1704 | "target": "64" 1705 | }, 1706 | { 1707 | "source": "76", 1708 | "target": "65" 1709 | }, 1710 | { 1711 | "source": "76", 1712 | "target": "66" 1713 | } 1714 | ], 1715 | "categories": [ 1716 | { 1717 | "name": "类目0" 1718 | }, 1719 | { 1720 | "name": "类目1" 1721 | }, 1722 | { 1723 | "name": "类目2" 1724 | }, 1725 | { 1726 | "name": "类目3" 1727 | }, 1728 | { 1729 | "name": "类目4" 1730 | }, 1731 | { 1732 | "name": "类目5" 1733 | }, 1734 | { 1735 | "name": "类目6" 1736 | }, 1737 | { 1738 | "name": "类目7" 1739 | }, 1740 | { 1741 | "name": "类目8" 1742 | } 1743 | ] 1744 | } -------------------------------------------------------------------------------- /src/frontend/public/rawdata_1.0.2-1.json: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": [ 3 | { 4 | "id": "0", 5 | "name": "原来你还在这里", 6 | "symbolSize": 30, 7 | "x": -87.93029, 8 | "y": 16.8120565, 9 | "value": 100, 10 | "category": 1 11 | }, 12 | { 13 | "id": "1", 14 | "name": "无心法师", 15 | "symbolSize": 30, 16 | "x": -108.08344, 17 | "y": -10.8853, 18 | "value": 100, 19 | "category": 0 20 | }, 21 | { 22 | "id": "2", 23 | "name": "仙剑奇侠传三", 24 | "symbolSize": 30, 25 | "x": 68.76357, 26 | "y": 92.29176, 27 | "value": 100, 28 | "category": 0 29 | }, 30 | { 31 | "id": "3", 32 | "name": "三生三世十里桃花", 33 | "symbolSize": 30, 34 | "x": 12.82404, 35 | "y": -50.26283, 36 | "value": 100, 37 | "category": 0 38 | }, 39 | { 40 | "id": "4", 41 | "name": "三生三世枕上书", 42 | "symbolSize": 30, 43 | "x": -139.30386, 44 | "y": 129.06424, 45 | "value": 100, 46 | "category": 0 47 | }, 48 | { 49 | "id": "5", 50 | "name": "何以笙箫默", 51 | "symbolSize": 30, 52 | "x": 117.26337, 53 | "y": -16.03506, 54 | "value": 100, 55 | "category": 1 56 | }, 57 | { 58 | "id": "6", 59 | "name": "三十而已", 60 | "symbolSize": 50, 61 | "x": -32.6012, 62 | "y": -45.16974, 63 | "value": 100, 64 | "category": 1 65 | }, 66 | { 67 | "id": "7", 68 | "name": "林玉芬", 69 | "symbolSize": 15, 70 | "x": -382.69568, 71 | "y": 475.09113, 72 | "value": 10, 73 | "category": 2 74 | }, 75 | { 76 | "id": "8", 77 | "name": "高林豹", 78 | "symbolSize": 15, 79 | "x": -320.384, 80 | "y": 387.17325, 81 | "value": 10, 82 | "category": 2 83 | }, 84 | { 85 | "id": "9", 86 | "name": "李国立", 87 | "symbolSize": 15, 88 | "x": -344.39832, 89 | "y": 451.16772, 90 | "value": 10, 91 | "category": 2 92 | }, 93 | { 94 | "id": "10", 95 | "name": "梁胜权", 96 | "symbolSize": 15, 97 | "x": -89.34107, 98 | "y": 234.56128, 99 | "value": 10, 100 | "category": 2 101 | }, 102 | { 103 | "id": "11", 104 | "name": "黄俊文", 105 | "symbolSize": 15, 106 | "x": -100.93029, 107 | "y": -26.8120565, 108 | "value": 10, 109 | "category": 2 110 | }, 111 | { 112 | "id": "12", 113 | "name": "余翠华", 114 | "symbolSize": 15, 115 | "x": -122.41348, 116 | "y": 210.37503, 117 | "value": 10, 118 | "category": 2 119 | }, 120 | { 121 | "id": "13", 122 | "name": "任海涛", 123 | "symbolSize": 15, 124 | "x": -194.31313, 125 | "y": 178.55301, 126 | "value": 10, 127 | "category": 2 128 | }, 129 | { 130 | "id": "14", 131 | "name": "杨玄", 132 | "symbolSize": 15, 133 | "x": -158.05168, 134 | "y": 201.99768, 135 | "value": 10, 136 | "category": 2 137 | }, 138 | { 139 | "id": "15", 140 | "name": "刘俊杰", 141 | "symbolSize": 15, 142 | "x": -127.701546, 143 | "y": 242.55057, 144 | "value": 10, 145 | "category": 2 146 | }, 147 | { 148 | "id": "16", 149 | "name": "张晓波", 150 | "symbolSize": 15, 151 | "x": -225.73984, 152 | "y": 82.41631, 153 | "value": 10, 154 | "category": 2 155 | }, 156 | { 157 | "id": "17", 158 | "name": "金国栋", 159 | "symbolSize": 15, 160 | "x": -516.55884, 161 | "y": -393.98975, 162 | "value": 10, 163 | "category": 3 164 | }, 165 | { 166 | "id": "18", 167 | "name": "徐子沅", 168 | "symbolSize": 15, 169 | "x": -464.79382, 170 | "y": -493.57944, 171 | "value": 10, 172 | "category": 3 173 | }, 174 | { 175 | "id": "19", 176 | "name": "肖志瑶", 177 | "symbolSize": 15, 178 | "x": -515.1624, 179 | "y": -456.9891, 180 | "value": 10, 181 | "category": 3 182 | }, 183 | { 184 | "id": "20", 185 | "name": "李楠", 186 | "symbolSize": 15, 187 | "x": -408.12122, 188 | "y": -464.5048, 189 | "value": 10, 190 | "category": 3 191 | }, 192 | { 193 | "id": "21", 194 | "name": "方羌羌", 195 | "symbolSize": 15, 196 | "x": -456.44113, 197 | "y": -425.13303, 198 | "value": 10, 199 | "category": 3 200 | }, 201 | { 202 | "id": "22", 203 | "name": "邓紫珊", 204 | "symbolSize": 15, 205 | "x": -459.1107, 206 | "y": -362.5133, 207 | "value": 10, 208 | "category": 3 209 | }, 210 | { 211 | "id": "23", 212 | "name": "弘伙", 213 | "symbolSize": 15, 214 | "x": -313.42786, 215 | "y": -289.44803, 216 | "value": 10, 217 | "category": 3 218 | }, 219 | { 220 | "id": "24", 221 | "name": "梁振华", 222 | "symbolSize": 15, 223 | "x": -74.6313396, 224 | "y": -273.8517, 225 | "value": 10, 226 | "category": 3 227 | }, 228 | { 229 | "id": "25", 230 | "name": "胡雅婷", 231 | "symbolSize": 15, 232 | "x": -182.80825, 233 | "y": -203.1144, 234 | "value": 10, 235 | "category": 3 236 | }, 237 | { 238 | "id": "26", 239 | "name": "顾漫", 240 | "symbolSize": 15, 241 | "x": 78.64646, 242 | "y": -431.512747, 243 | "value": 10, 244 | "category": 3 245 | }, 246 | { 247 | "id": "27", 248 | "name": "墨宝非宝", 249 | "symbolSize": 15, 250 | "x": -281.46074, 251 | "y": -204.20204, 252 | "value": 10, 253 | "category": 3 254 | }, 255 | { 256 | "id": "28", 257 | "name": "张英姬", 258 | "symbolSize": 15, 259 | "x": -385.2226, 260 | "y": -393.5572, 261 | "value": 10, 262 | "category": 3 263 | }, 264 | { 265 | "id": "29", 266 | "name": "蔡艺侬", 267 | "symbolSize": 15, 268 | "x": -385.6842, 269 | "y": -20.206686, 270 | "value": 10, 271 | "category": 4 272 | }, 273 | { 274 | "id": "30", 275 | "name": "赵洁", 276 | "symbolSize": 15, 277 | "x": -403.92447, 278 | "y": -197.69823, 279 | "value": 10, 280 | "category": 4 281 | }, 282 | { 283 | "id": "31", 284 | "name": "高琛", 285 | "symbolSize": 15, 286 | "x": -281.4253, 287 | "y": -158.45137, 288 | "value": 10, 289 | "category": 4 290 | }, 291 | { 292 | "id": "32", 293 | "name": "房迎", 294 | "symbolSize": 15, 295 | "x": -339.77908, 296 | "y": -184.69139, 297 | "value": 10, 298 | "category": 4 299 | }, 300 | { 301 | "id": "33", 302 | "name": "陈菲", 303 | "symbolSize": 15, 304 | "x": -234.6001, 305 | "y": -113.15067, 306 | "value": 10, 307 | "category": 4 308 | }, 309 | { 310 | "id": "34", 311 | "name": "徐晓鸥", 312 | "symbolSize": 15, 313 | "x": -387.84915, 314 | "y": 58.7059, 315 | "value": 10, 316 | "category": 4 317 | }, 318 | { 319 | "id": "35", 320 | "name": "杨子姗", 321 | "symbolSize": 15, 322 | "x": 338.2307, 323 | "y": 87.48405, 324 | "value": 10, 325 | "category": 5 326 | }, 327 | { 328 | "id": "36", 329 | "name": "韩东君", 330 | "symbolSize": 15, 331 | "x": 753.26874, 332 | "y": 58.94648, 333 | "value": 10, 334 | "category": 5 335 | }, 336 | { 337 | "id": "37", 338 | "name": "李程彬", 339 | "symbolSize": 15, 340 | "x": 486.44904, 341 | "y": 140.05937, 342 | "value": 10, 343 | "category": 5 344 | }, 345 | { 346 | "id": "38", 347 | "name": "苏青", 348 | "symbolSize": 15, 349 | "x": 946.7876, 350 | "y": 123.38005, 351 | "value": 10, 352 | "category": 5 353 | }, 354 | { 355 | "id": "39", 356 | "name": "蓝盈莹", 357 | "symbolSize": 15, 358 | "x": 336.49738, 359 | "y": -269.55914, 360 | "value": 10, 361 | "category": 5 362 | }, 363 | { 364 | "id": "40", 365 | "name": "檀健次", 366 | "symbolSize": 15, 367 | "x": 229.187843, 368 | "y": -460.13132, 369 | "value": 10, 370 | "category": 5 371 | }, 372 | { 373 | "id": "41", 374 | "name": "温心", 375 | "symbolSize": 15, 376 | "x": 238.36697, 377 | "y": -210.00926, 378 | "value": 10, 379 | "category": 5 380 | }, 381 | { 382 | "id": "42", 383 | "name": "李兰迪", 384 | "symbolSize": 15, 385 | "x": 189.69513, 386 | "y": -346.50662, 387 | "value": 10, 388 | "category": 5 389 | }, 390 | { 391 | "id": "43", 392 | "name": "高圣远", 393 | "symbolSize": 15, 394 | "x": 187.00418, 395 | "y": -145.02663, 396 | "value": 10, 397 | "category": 5 398 | }, 399 | { 400 | "id": "44", 401 | "name": "胡先煦", 402 | "symbolSize": 15, 403 | "x": 252.99521, 404 | "y": 129.87549, 405 | "value": 10, 406 | "category": 5 407 | }, 408 | { 409 | "id": "45", 410 | "name": "金晨", 411 | "symbolSize": 15, 412 | "x": 296.07935, 413 | "y": 163.11964, 414 | "value": 10, 415 | "category": 5 416 | }, 417 | { 418 | "id": "46", 419 | "name": "陈瑶", 420 | "symbolSize": 15, 421 | "x": 550.3201, 422 | "y": 522.4031, 423 | "value": 10, 424 | "category": 5 425 | }, 426 | { 427 | "id": "47", 428 | "name": "张若昀", 429 | "symbolSize": 15, 430 | "x": 488.13535, 431 | "y": 356.8573, 432 | "value": 10, 433 | "category": 5 434 | }, 435 | { 436 | "id": "48", 437 | "name": "王彦霖", 438 | "symbolSize": 15, 439 | "x": 387.89572, 440 | "y": 110.462326, 441 | "value": 10, 442 | "category": 5 443 | }, 444 | { 445 | "id": "49", 446 | "name": "Mike", 447 | "symbolSize": 15, 448 | "x": 126.4831, 449 | "y": 68.10622, 450 | "value": 10, 451 | "category": 5 452 | }, 453 | { 454 | "id": "50", 455 | "name": "胡歌", 456 | "symbolSize": 15, 457 | "x": 127.07365, 458 | "y": -113.05923, 459 | "value": 10, 460 | "category": 5 461 | }, 462 | { 463 | "id": "51", 464 | "name": "霍建华", 465 | "symbolSize": 15, 466 | "x": 162.63559, 467 | "y": 117.6565, 468 | "value": 10, 469 | "category": 5 470 | }, 471 | { 472 | "id": "52", 473 | "name": "杨幂", 474 | "symbolSize": 15, 475 | "x": 353.66415, 476 | "y": -205.89165, 477 | "value": 10, 478 | "category": 5 479 | }, 480 | { 481 | "id": "53", 482 | "name": "刘诗诗", 483 | "symbolSize": 15, 484 | "x": 165.43939, 485 | "y": 339.7736, 486 | "value": 10, 487 | "category": 5 488 | }, 489 | { 490 | "id": "54", 491 | "name": "唐嫣", 492 | "symbolSize": 15, 493 | "x": 137.69348, 494 | "y": 196.1069, 495 | "value": 10, 496 | "category": 5 497 | }, 498 | { 499 | "id": "55", 500 | "name": "赵又廷", 501 | "symbolSize": 15, 502 | "x": 206.44687, 503 | "y": -113.805411, 504 | "value": 10, 505 | "category": 5 506 | }, 507 | { 508 | "id": "56", 509 | "name": "张智尧", 510 | "symbolSize": 15, 511 | "x": 194.82993, 512 | "y": 224.78036, 513 | "value": 10, 514 | "category": 5 515 | }, 516 | { 517 | "id": "57", 518 | "name": "迪丽热巴", 519 | "symbolSize": 15, 520 | "x": 597.6618, 521 | "y": 135.18481, 522 | "value": 10, 523 | "category": 5 524 | }, 525 | { 526 | "id": "58", 527 | "name": "高伟光", 528 | "symbolSize": 15, 529 | "x": 355.78366, 530 | "y": -74.882454, 531 | "value": 10, 532 | "category": 5 533 | }, 534 | { 535 | "id": "59", 536 | "name": "黄梦莹", 537 | "symbolSize": 15, 538 | "x": 515.2961, 539 | "y": -46.167564, 540 | "value": 10, 541 | "category": 5 542 | }, 543 | { 544 | "id": "60", 545 | "name": "张彬彬", 546 | "symbolSize": 15, 547 | "x": 614.29285, 548 | "y": -69.3104, 549 | "value": 10, 550 | "category": 5 551 | }, 552 | { 553 | "id": "61", 554 | "name": "于朦胧", 555 | "symbolSize": 15, 556 | "x": 550.1917, 557 | "y": -128.17537, 558 | "value": 10, 559 | "category": 5 560 | }, 561 | { 562 | "id": "62", 563 | "name": "刘芮麟", 564 | "symbolSize": 15, 565 | "x": 436.17184, 566 | "y": -12.7286825, 567 | "value": 10, 568 | "category": 5 569 | }, 570 | { 571 | "id": "63", 572 | "name": "王骁", 573 | "symbolSize": 15, 574 | "x": 602.55225, 575 | "y": 16.421427, 576 | "value": 10, 577 | "category": 5 578 | }, 579 | { 580 | "id": "64", 581 | "name": "陈楚河", 582 | "symbolSize": 15, 583 | "x": 455.81955, 584 | "y": -115.45826, 585 | "value": 10, 586 | "category": 5 587 | }, 588 | { 589 | "id": "65", 590 | "name": "郭品超", 591 | "symbolSize": 15, 592 | "x": 516.40784, 593 | "y": 47.242233, 594 | "value": 10, 595 | "category": 5 596 | }, 597 | { 598 | "id": "66", 599 | "name": "刘玥霏", 600 | "symbolSize": 15, 601 | "x": 646.4313, 602 | "y": -151.06331, 603 | "value": 10, 604 | "category": 5 605 | }, 606 | { 607 | "id": "67", 608 | "name": "钟汉良", 609 | "symbolSize": 15, 610 | "x": 668.9568, 611 | "y": 204.65488, 612 | "value": 10, 613 | "category": 5 614 | }, 615 | { 616 | "id": "68", 617 | "name": "谭凯", 618 | "symbolSize": 15, 619 | "x": 78.4799, 620 | "y": -347.15146, 621 | "value": 10, 622 | "category": 5 623 | }, 624 | { 625 | "id": "69", 626 | "name": "杨玏", 627 | "symbolSize": 15, 628 | "x": 150.35959, 629 | "y": -298.50797, 630 | "value": 10, 631 | "category": 5 632 | }, 633 | { 634 | "id": "70", 635 | "name": "菅纫姿", 636 | "symbolSize": 15, 637 | "x": 137.3717, 638 | "y": -410.2809, 639 | "value": 10, 640 | "category": 5 641 | }, 642 | { 643 | "id": "71", 644 | "name": "米露", 645 | "symbolSize": 15, 646 | "x": 234.87747, 647 | "y": -400.85983, 648 | "value": 10, 649 | "category": 5 650 | }, 651 | { 652 | "id": "72", 653 | "name": "江疏影", 654 | "symbolSize": 15, 655 | "x": 40.942253, 656 | "y": 113.78272, 657 | "value": 10, 658 | "category": 5 659 | }, 660 | { 661 | "id": "73", 662 | "name": "童瑶", 663 | "symbolSize": 15, 664 | "x": 437.939, 665 | "y": 291.58234, 666 | "value": 10, 667 | "category": 5 668 | }, 669 | { 670 | "id": "74", 671 | "name": "毛晓彤", 672 | "symbolSize": 15, 673 | "x": 466.04922, 674 | "y": 283.3606, 675 | "value": 10, 676 | "category": 5 677 | }, 678 | { 679 | "id": "75", 680 | "name": "李泽锋", 681 | "symbolSize": 15, 682 | "x": 238.79364, 683 | "y": -314.06345, 684 | "value": 10, 685 | "category": 5 686 | } 687 | ], 688 | "links": [ 689 | { 690 | "source": "7", 691 | "target": "0" 692 | }, 693 | { 694 | "source": "17", 695 | "target": "0" 696 | }, 697 | { 698 | "source": "29", 699 | "target": "0" 700 | }, 701 | { 702 | "source": "35", 703 | "target": "0" 704 | }, 705 | { 706 | "source": "36", 707 | "target": "0" 708 | }, 709 | { 710 | "source": "37", 711 | "target": "0" 712 | }, 713 | { 714 | "source": "38", 715 | "target": "0" 716 | }, 717 | { 718 | "source": "39", 719 | "target": "0" 720 | }, 721 | { 722 | "source": "40", 723 | "target": "0" 724 | }, 725 | { 726 | "source": "41", 727 | "target": "0" 728 | }, 729 | { 730 | "source": "42", 731 | "target": "0" 732 | }, 733 | { 734 | "source": "43", 735 | "target": "0" 736 | }, 737 | { 738 | "source": "44", 739 | "target": "0" 740 | }, 741 | { 742 | "source": "7", 743 | "target": "1" 744 | }, 745 | { 746 | "source": "8", 747 | "target": "1" 748 | }, 749 | { 750 | "source": "9", 751 | "target": "1" 752 | }, 753 | { 754 | "source": "18", 755 | "target": "1" 756 | }, 757 | { 758 | "source": "19", 759 | "target": "1" 760 | }, 761 | { 762 | "source": "20", 763 | "target": "1" 764 | }, 765 | { 766 | "source": "21", 767 | "target": "1" 768 | }, 769 | { 770 | "source": "29", 771 | "target": "1" 772 | }, 773 | { 774 | "source": "36", 775 | "target": "1" 776 | }, 777 | { 778 | "source": "45", 779 | "target": "1" 780 | }, 781 | { 782 | "source": "46", 783 | "target": "1" 784 | }, 785 | { 786 | "source": "47", 787 | "target": "1" 788 | }, 789 | { 790 | "source": "48", 791 | "target": "1" 792 | }, 793 | { 794 | "source": "49", 795 | "target": "1" 796 | }, 797 | { 798 | "source": "9", 799 | "target": "2" 800 | }, 801 | { 802 | "source": "10", 803 | "target": "2" 804 | }, 805 | { 806 | "source": "7", 807 | "target": "2" 808 | }, 809 | { 810 | "source": "11", 811 | "target": "2" 812 | }, 813 | { 814 | "source": "22", 815 | "target": "2" 816 | }, 817 | { 818 | "source": "29", 819 | "target": "2" 820 | }, 821 | { 822 | "source": "50", 823 | "target": "2" 824 | }, 825 | { 826 | "source": "51", 827 | "target": "2" 828 | }, 829 | { 830 | "source": "52", 831 | "target": "2" 832 | }, 833 | { 834 | "source": "53", 835 | "target": "2" 836 | }, 837 | { 838 | "source": "54", 839 | "target": "2" 840 | }, 841 | { 842 | "source": "7", 843 | "target": "3" 844 | }, 845 | { 846 | "source": "12", 847 | "target": "3" 848 | }, 849 | { 850 | "source": "13", 851 | "target": "3" 852 | }, 853 | { 854 | "source": "23", 855 | "target": "3" 856 | }, 857 | { 858 | "source": "52", 859 | "target": "3" 860 | }, 861 | { 862 | "source": "55", 863 | "target": "3" 864 | }, 865 | { 866 | "source": "56", 867 | "target": "3" 868 | }, 869 | { 870 | "source": "57", 871 | "target": "3" 872 | }, 873 | { 874 | "source": "58", 875 | "target": "3" 876 | }, 877 | { 878 | "source": "59", 879 | "target": "3" 880 | }, 881 | { 882 | "source": "60", 883 | "target": "3" 884 | }, 885 | { 886 | "source": "61", 887 | "target": "3" 888 | }, 889 | { 890 | "source": "62", 891 | "target": "3" 892 | }, 893 | { 894 | "source": "63", 895 | "target": "3" 896 | }, 897 | { 898 | "source": "14", 899 | "target": "4" 900 | }, 901 | { 902 | "source": "24", 903 | "target": "4" 904 | }, 905 | { 906 | "source": "25", 907 | "target": "4" 908 | }, 909 | { 910 | "source": "30", 911 | "target": "4" 912 | }, 913 | { 914 | "source": "31", 915 | "target": "4" 916 | }, 917 | { 918 | "source": "57", 919 | "target": "4" 920 | }, 921 | { 922 | "source": "58", 923 | "target": "4" 924 | }, 925 | { 926 | "source": "64", 927 | "target": "4" 928 | }, 929 | { 930 | "source": "65", 931 | "target": "4" 932 | }, 933 | { 934 | "source": "66", 935 | "target": "4" 936 | }, 937 | { 938 | "source": "62", 939 | "target": "4" 940 | }, 941 | { 942 | "source": "63", 943 | "target": "4" 944 | }, 945 | { 946 | "source": "15", 947 | "target": "5" 948 | }, 949 | { 950 | "source": "26", 951 | "target": "5" 952 | }, 953 | { 954 | "source": "27", 955 | "target": "5" 956 | }, 957 | { 958 | "source": "17", 959 | "target": "5" 960 | }, 961 | { 962 | "source": "32", 963 | "target": "5" 964 | }, 965 | { 966 | "source": "67", 967 | "target": "5" 968 | }, 969 | { 970 | "source": "54", 971 | "target": "5" 972 | }, 973 | { 974 | "source": "68", 975 | "target": "5" 976 | }, 977 | { 978 | "source": "69", 979 | "target": "5" 980 | }, 981 | { 982 | "source": "70", 983 | "target": "5" 984 | }, 985 | { 986 | "source": "71", 987 | "target": "5" 988 | }, 989 | { 990 | "source": "16", 991 | "target": "6" 992 | }, 993 | { 994 | "source": "28", 995 | "target": "6" 996 | }, 997 | { 998 | "source": "33", 999 | "target": "6" 1000 | }, 1001 | { 1002 | "source": "34", 1003 | "target": "6" 1004 | }, 1005 | { 1006 | "source": "72", 1007 | "target": "6" 1008 | }, 1009 | { 1010 | "source": "73", 1011 | "target": "6" 1012 | }, 1013 | { 1014 | "source": "69", 1015 | "target": "6" 1016 | }, 1017 | { 1018 | "source": "74", 1019 | "target": "6" 1020 | }, 1021 | { 1022 | "source": "75", 1023 | "target": "6" 1024 | } 1025 | ], 1026 | "categories": [ 1027 | { 1028 | "name": "玄幻" 1029 | }, 1030 | { 1031 | "name": "都市" 1032 | }, 1033 | { 1034 | "name": "导演" 1035 | }, 1036 | { 1037 | "name": "编剧" 1038 | }, 1039 | { 1040 | "name": "制片人" 1041 | }, 1042 | { 1043 | "name": "演员" 1044 | } 1045 | ] 1046 | } -------------------------------------------------------------------------------- /src/frontend/public/rawdata_1.0.2-2.json: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": [ 3 | { 4 | "id": "0", 5 | "name": "原来你还在这里", 6 | "symbolSize": 30, 7 | "x": -87.93029, 8 | "y": -216.8120565, 9 | "value": 100, 10 | "category": 1 11 | }, 12 | { 13 | "id": "1", 14 | "name": "无心法师", 15 | "symbolSize": 30, 16 | "x": -208.08344, 17 | "y": -10.8853, 18 | "value": 100, 19 | "category": 0 20 | }, 21 | { 22 | "id": "2", 23 | "name": "仙剑奇侠传三", 24 | "symbolSize": 30, 25 | "x": 68.76357, 26 | "y": 92.29176, 27 | "value": 100, 28 | "category": 0 29 | }, 30 | { 31 | "id": "3", 32 | "name": "三生三世十里桃花", 33 | "symbolSize": 30, 34 | "x": 12.82404, 35 | "y": -250.26283, 36 | "value": 100, 37 | "category": 0 38 | }, 39 | { 40 | "id": "4", 41 | "name": "三生三世枕上书", 42 | "symbolSize": 30, 43 | "x": -139.30386, 44 | "y": 129.06424, 45 | "value": 100, 46 | "category": 0 47 | }, 48 | { 49 | "id": "5", 50 | "name": "何以笙箫默", 51 | "symbolSize": 30, 52 | "x": 217.26337, 53 | "y": -16.03506, 54 | "value": 100, 55 | "category": 1 56 | }, 57 | { 58 | "id": "6", 59 | "name": "三十而已", 60 | "symbolSize": 30, 61 | "x": 32.6012, 62 | "y": -145.16974, 63 | "value": 100, 64 | "category": 1 65 | }, 66 | { 67 | "id": "7", 68 | "name": "林玉芬", 69 | "symbolSize": 15, 70 | "x": -382.69568, 71 | "y": 475.09113, 72 | "value": 10, 73 | "category": 2 74 | }, 75 | { 76 | "id": "8", 77 | "name": "高林豹", 78 | "symbolSize": 15, 79 | "x": -320.384, 80 | "y": 387.17325, 81 | "value": 10, 82 | "category": 2 83 | }, 84 | { 85 | "id": "9", 86 | "name": "李国立", 87 | "symbolSize": 15, 88 | "x": -344.39832, 89 | "y": 451.16772, 90 | "value": 10, 91 | "category": 2 92 | }, 93 | { 94 | "id": "10", 95 | "name": "梁胜权", 96 | "symbolSize": 15, 97 | "x": -89.34107, 98 | "y": 534.56128, 99 | "value": 10, 100 | "category": 2 101 | }, 102 | { 103 | "id": "11", 104 | "name": "黄俊文", 105 | "symbolSize": 15, 106 | "x": -100.93029, 107 | "y": 426.8120565, 108 | "value": 10, 109 | "category": 2 110 | }, 111 | { 112 | "id": "12", 113 | "name": "余翠华", 114 | "symbolSize": 15, 115 | "x": -122.41348, 116 | "y": 510.37503, 117 | "value": 10, 118 | "category": 2 119 | }, 120 | { 121 | "id": "13", 122 | "name": "任海涛", 123 | "symbolSize": 15, 124 | "x": -194.31313, 125 | "y": 478.55301, 126 | "value": 10, 127 | "category": 2 128 | }, 129 | { 130 | "id": "14", 131 | "name": "杨玄", 132 | "symbolSize": 15, 133 | "x": -158.05168, 134 | "y": 401.99768, 135 | "value": 10, 136 | "category": 2 137 | }, 138 | { 139 | "id": "15", 140 | "name": "刘俊杰", 141 | "symbolSize": 15, 142 | "x": -127.701546, 143 | "y": 542.55057, 144 | "value": 10, 145 | "category": 2 146 | }, 147 | { 148 | "id": "16", 149 | "name": "张晓波", 150 | "symbolSize": 15, 151 | "x": -225.73984, 152 | "y": 482.41631, 153 | "value": 10, 154 | "category": 2 155 | }, 156 | { 157 | "id": "17", 158 | "name": "金国栋", 159 | "symbolSize": 15, 160 | "x": -516.55884, 161 | "y": -393.98975, 162 | "value": 10, 163 | "category": 3 164 | }, 165 | { 166 | "id": "18", 167 | "name": "徐子沅", 168 | "symbolSize": 15, 169 | "x": -464.79382, 170 | "y": -493.57944, 171 | "value": 10, 172 | "category": 3 173 | }, 174 | { 175 | "id": "19", 176 | "name": "肖志瑶", 177 | "symbolSize": 15, 178 | "x": -515.1624, 179 | "y": -456.9891, 180 | "value": 10, 181 | "category": 3 182 | }, 183 | { 184 | "id": "20", 185 | "name": "李楠", 186 | "symbolSize": 15, 187 | "x": -408.12122, 188 | "y": -464.5048, 189 | "value": 10, 190 | "category": 3 191 | }, 192 | { 193 | "id": "21", 194 | "name": "方羌羌", 195 | "symbolSize": 15, 196 | "x": -456.44113, 197 | "y": -425.13303, 198 | "value": 10, 199 | "category": 3 200 | }, 201 | { 202 | "id": "22", 203 | "name": "邓紫珊", 204 | "symbolSize": 15, 205 | "x": -459.1107, 206 | "y": -362.5133, 207 | "value": 10, 208 | "category": 3 209 | }, 210 | { 211 | "id": "23", 212 | "name": "弘伙", 213 | "symbolSize": 15, 214 | "x": -313.42786, 215 | "y": -289.44803, 216 | "value": 10, 217 | "category": 3 218 | }, 219 | { 220 | "id": "24", 221 | "name": "梁振华", 222 | "symbolSize": 15, 223 | "x": -74.6313396, 224 | "y": -273.8517, 225 | "value": 10, 226 | "category": 3 227 | }, 228 | { 229 | "id": "25", 230 | "name": "胡雅婷", 231 | "symbolSize": 15, 232 | "x": -182.80825, 233 | "y": -403.1144, 234 | "value": 10, 235 | "category": 3 236 | }, 237 | { 238 | "id": "26", 239 | "name": "顾漫", 240 | "symbolSize": 15, 241 | "x": -378.64646, 242 | "y": -431.512747, 243 | "value": 10, 244 | "category": 3 245 | }, 246 | { 247 | "id": "27", 248 | "name": "墨宝非宝", 249 | "symbolSize": 15, 250 | "x": -181.46074, 251 | "y": -304.20204, 252 | "value": 10, 253 | "category": 3 254 | }, 255 | { 256 | "id": "28", 257 | "name": "张英姬", 258 | "symbolSize": 15, 259 | "x": -385.2226, 260 | "y": -393.5572, 261 | "value": 10, 262 | "category": 3 263 | }, 264 | { 265 | "id": "29", 266 | "name": "蔡艺侬", 267 | "symbolSize": 15, 268 | "x": -385.6842, 269 | "y": -20.206686, 270 | "value": 10, 271 | "category": 4 272 | }, 273 | { 274 | "id": "30", 275 | "name": "赵洁", 276 | "symbolSize": 15, 277 | "x": -403.92447, 278 | "y": -197.69823, 279 | "value": 10, 280 | "category": 4 281 | }, 282 | { 283 | "id": "31", 284 | "name": "高琛", 285 | "symbolSize": 15, 286 | "x": -281.4253, 287 | "y": -158.45137, 288 | "value": 10, 289 | "category": 4 290 | }, 291 | { 292 | "id": "32", 293 | "name": "房迎", 294 | "symbolSize": 15, 295 | "x": -339.77908, 296 | "y": -184.69139, 297 | "value": 10, 298 | "category": 4 299 | }, 300 | { 301 | "id": "33", 302 | "name": "陈菲", 303 | "symbolSize": 15, 304 | "x": -234.6001, 305 | "y": -113.15067, 306 | "value": 10, 307 | "category": 4 308 | }, 309 | { 310 | "id": "34", 311 | "name": "徐晓鸥", 312 | "symbolSize": 15, 313 | "x": -387.84915, 314 | "y": 58.7059, 315 | "value": 10, 316 | "category": 4 317 | }, 318 | { 319 | "id": "35", 320 | "name": "杨子姗", 321 | "symbolSize": 15, 322 | "x": 338.2307, 323 | "y": 87.48405, 324 | "value": 10, 325 | "category": 5 326 | }, 327 | { 328 | "id": "36", 329 | "name": "韩东君", 330 | "symbolSize": 15, 331 | "x": 753.26874, 332 | "y": 58.94648, 333 | "value": 10, 334 | "category": 5 335 | }, 336 | { 337 | "id": "37", 338 | "name": "李程彬", 339 | "symbolSize": 15, 340 | "x": 486.44904, 341 | "y": 140.05937, 342 | "value": 10, 343 | "category": 5 344 | }, 345 | { 346 | "id": "38", 347 | "name": "苏青", 348 | "symbolSize": 15, 349 | "x": 946.7876, 350 | "y": 123.38005, 351 | "value": 10, 352 | "category": 5 353 | }, 354 | { 355 | "id": "39", 356 | "name": "蓝盈莹", 357 | "symbolSize": 15, 358 | "x": 336.49738, 359 | "y": -269.55914, 360 | "value": 10, 361 | "category": 5 362 | }, 363 | { 364 | "id": "40", 365 | "name": "檀健次", 366 | "symbolSize": 15, 367 | "x": 229.187843, 368 | "y": -460.13132, 369 | "value": 10, 370 | "category": 5 371 | }, 372 | { 373 | "id": "41", 374 | "name": "温心", 375 | "symbolSize": 15, 376 | "x": 238.36697, 377 | "y": -210.00926, 378 | "value": 10, 379 | "category": 5 380 | }, 381 | { 382 | "id": "42", 383 | "name": "李兰迪", 384 | "symbolSize": 15, 385 | "x": 189.69513, 386 | "y": -346.50662, 387 | "value": 10, 388 | "category": 5 389 | }, 390 | { 391 | "id": "43", 392 | "name": "高圣远", 393 | "symbolSize": 15, 394 | "x": 187.00418, 395 | "y": -145.02663, 396 | "value": 10, 397 | "category": 5 398 | }, 399 | { 400 | "id": "44", 401 | "name": "胡先煦", 402 | "symbolSize": 15, 403 | "x": 252.99521, 404 | "y": 129.87549, 405 | "value": 10, 406 | "category": 5 407 | }, 408 | { 409 | "id": "45", 410 | "name": "金晨", 411 | "symbolSize": 15, 412 | "x": 296.07935, 413 | "y": 163.11964, 414 | "value": 10, 415 | "category": 5 416 | }, 417 | { 418 | "id": "46", 419 | "name": "陈瑶", 420 | "symbolSize": 15, 421 | "x": 550.3201, 422 | "y": 522.4031, 423 | "value": 10, 424 | "category": 5 425 | }, 426 | { 427 | "id": "47", 428 | "name": "张若昀", 429 | "symbolSize": 15, 430 | "x": 488.13535, 431 | "y": 356.8573, 432 | "value": 10, 433 | "category": 5 434 | }, 435 | { 436 | "id": "48", 437 | "name": "王彦霖", 438 | "symbolSize": 15, 439 | "x": 387.89572, 440 | "y": 110.462326, 441 | "value": 10, 442 | "category": 5 443 | }, 444 | { 445 | "id": "49", 446 | "name": "Mike", 447 | "symbolSize": 15, 448 | "x": 126.4831, 449 | "y": 168.10622, 450 | "value": 10, 451 | "category": 5 452 | }, 453 | { 454 | "id": "50", 455 | "name": "胡歌", 456 | "symbolSize": 15, 457 | "x": 127.07365, 458 | "y": -313.05923, 459 | "value": 10, 460 | "category": 5 461 | }, 462 | { 463 | "id": "51", 464 | "name": "霍建华", 465 | "symbolSize": 15, 466 | "x": 162.63559, 467 | "y": 317.6565, 468 | "value": 10, 469 | "category": 5 470 | }, 471 | { 472 | "id": "52", 473 | "name": "杨幂", 474 | "symbolSize": 15, 475 | "x": 353.66415, 476 | "y": -205.89165, 477 | "value": 10, 478 | "category": 5 479 | }, 480 | { 481 | "id": "53", 482 | "name": "刘诗诗", 483 | "symbolSize": 15, 484 | "x": 165.43939, 485 | "y": 339.7736, 486 | "value": 10, 487 | "category": 5 488 | }, 489 | { 490 | "id": "54", 491 | "name": "唐嫣", 492 | "symbolSize": 15, 493 | "x": 137.69348, 494 | "y": 496.1069, 495 | "value": 10, 496 | "category": 5 497 | }, 498 | { 499 | "id": "55", 500 | "name": "赵又廷", 501 | "symbolSize": 15, 502 | "x": 206.44687, 503 | "y": -413.805411, 504 | "value": 10, 505 | "category": 5 506 | }, 507 | { 508 | "id": "56", 509 | "name": "张智尧", 510 | "symbolSize": 15, 511 | "x": 194.82993, 512 | "y": 324.78036, 513 | "value": 10, 514 | "category": 5 515 | }, 516 | { 517 | "id": "57", 518 | "name": "迪丽热巴", 519 | "symbolSize": 15, 520 | "x": 597.6618, 521 | "y": 275.18481, 522 | "value": 10, 523 | "category": 5 524 | }, 525 | { 526 | "id": "58", 527 | "name": "高伟光", 528 | "symbolSize": 15, 529 | "x": 355.78366, 530 | "y": -74.882454, 531 | "value": 10, 532 | "category": 5 533 | }, 534 | { 535 | "id": "59", 536 | "name": "黄梦莹", 537 | "symbolSize": 15, 538 | "x": 515.2961, 539 | "y": -46.167564, 540 | "value": 10, 541 | "category": 5 542 | }, 543 | { 544 | "id": "60", 545 | "name": "张彬彬", 546 | "symbolSize": 15, 547 | "x": 614.29285, 548 | "y": -69.3104, 549 | "value": 10, 550 | "category": 5 551 | }, 552 | { 553 | "id": "61", 554 | "name": "于朦胧", 555 | "symbolSize": 15, 556 | "x": 550.1917, 557 | "y": -128.17537, 558 | "value": 10, 559 | "category": 5 560 | }, 561 | { 562 | "id": "62", 563 | "name": "刘芮麟", 564 | "symbolSize": 15, 565 | "x": 436.17184, 566 | "y": -12.7286825, 567 | "value": 10, 568 | "category": 5 569 | }, 570 | { 571 | "id": "63", 572 | "name": "王骁", 573 | "symbolSize": 15, 574 | "x": 602.55225, 575 | "y": 16.421427, 576 | "value": 10, 577 | "category": 5 578 | }, 579 | { 580 | "id": "64", 581 | "name": "陈楚河", 582 | "symbolSize": 15, 583 | "x": 455.81955, 584 | "y": -115.45826, 585 | "value": 10, 586 | "category": 5 587 | }, 588 | { 589 | "id": "65", 590 | "name": "郭品超", 591 | "symbolSize": 15, 592 | "x": 516.40784, 593 | "y": 47.242233, 594 | "value": 10, 595 | "category": 5 596 | }, 597 | { 598 | "id": "66", 599 | "name": "刘玥霏", 600 | "symbolSize": 15, 601 | "x": 646.4313, 602 | "y": -151.06331, 603 | "value": 10, 604 | "category": 5 605 | }, 606 | { 607 | "id": "67", 608 | "name": "钟汉良", 609 | "symbolSize": 15, 610 | "x": 668.9568, 611 | "y": 204.65488, 612 | "value": 10, 613 | "category": 5 614 | }, 615 | { 616 | "id": "68", 617 | "name": "谭凯", 618 | "symbolSize": 15, 619 | "x": 278.4799, 620 | "y": -347.15146, 621 | "value": 10, 622 | "category": 5 623 | }, 624 | { 625 | "id": "69", 626 | "name": "杨玏", 627 | "symbolSize": 15, 628 | "x": 150.35959, 629 | "y": -298.50797, 630 | "value": 10, 631 | "category": 5 632 | }, 633 | { 634 | "id": "70", 635 | "name": "菅纫姿", 636 | "symbolSize": 15, 637 | "x": 137.3717, 638 | "y": -410.2809, 639 | "value": 10, 640 | "category": 5 641 | }, 642 | { 643 | "id": "71", 644 | "name": "米露", 645 | "symbolSize": 15, 646 | "x": 234.87747, 647 | "y": -400.85983, 648 | "value": 10, 649 | "category": 5 650 | }, 651 | { 652 | "id": "72", 653 | "name": "江疏影", 654 | "symbolSize": 15, 655 | "x": 540.942253, 656 | "y": 213.78272, 657 | "value": 10, 658 | "category": 5 659 | }, 660 | { 661 | "id": "73", 662 | "name": "童瑶", 663 | "symbolSize": 15, 664 | "x": 437.939, 665 | "y": 291.58234, 666 | "value": 10, 667 | "category": 5 668 | }, 669 | { 670 | "id": "74", 671 | "name": "毛晓彤", 672 | "symbolSize": 15, 673 | "x": 466.04922, 674 | "y": 283.3606, 675 | "value": 10, 676 | "category": 5 677 | }, 678 | { 679 | "id": "75", 680 | "name": "李泽锋", 681 | "symbolSize": 15, 682 | "x": 238.79364, 683 | "y": -314.06345, 684 | "value": 10, 685 | "category": 5 686 | } 687 | ], 688 | "links": [ 689 | { 690 | "source": "7", 691 | "target": "0" 692 | }, 693 | { 694 | "source": "17", 695 | "target": "0" 696 | }, 697 | { 698 | "source": "29", 699 | "target": "0" 700 | }, 701 | { 702 | "source": "35", 703 | "target": "0" 704 | }, 705 | { 706 | "source": "36", 707 | "target": "0" 708 | }, 709 | { 710 | "source": "37", 711 | "target": "0" 712 | }, 713 | { 714 | "source": "38", 715 | "target": "0" 716 | }, 717 | { 718 | "source": "39", 719 | "target": "0" 720 | }, 721 | { 722 | "source": "40", 723 | "target": "0" 724 | }, 725 | { 726 | "source": "41", 727 | "target": "0" 728 | }, 729 | { 730 | "source": "42", 731 | "target": "0" 732 | }, 733 | { 734 | "source": "43", 735 | "target": "0" 736 | }, 737 | { 738 | "source": "44", 739 | "target": "0" 740 | }, 741 | { 742 | "source": "7", 743 | "target": "1" 744 | }, 745 | { 746 | "source": "8", 747 | "target": "1" 748 | }, 749 | { 750 | "source": "9", 751 | "target": "1" 752 | }, 753 | { 754 | "source": "18", 755 | "target": "1" 756 | }, 757 | { 758 | "source": "19", 759 | "target": "1" 760 | }, 761 | { 762 | "source": "20", 763 | "target": "1" 764 | }, 765 | { 766 | "source": "21", 767 | "target": "1" 768 | }, 769 | { 770 | "source": "29", 771 | "target": "1" 772 | }, 773 | { 774 | "source": "36", 775 | "target": "1" 776 | }, 777 | { 778 | "source": "45", 779 | "target": "1" 780 | }, 781 | { 782 | "source": "46", 783 | "target": "1" 784 | }, 785 | { 786 | "source": "47", 787 | "target": "1" 788 | }, 789 | { 790 | "source": "48", 791 | "target": "1" 792 | }, 793 | { 794 | "source": "49", 795 | "target": "1" 796 | }, 797 | { 798 | "source": "9", 799 | "target": "2" 800 | }, 801 | { 802 | "source": "10", 803 | "target": "2" 804 | }, 805 | { 806 | "source": "7", 807 | "target": "2" 808 | }, 809 | { 810 | "source": "11", 811 | "target": "2" 812 | }, 813 | { 814 | "source": "22", 815 | "target": "2" 816 | }, 817 | { 818 | "source": "29", 819 | "target": "2" 820 | }, 821 | { 822 | "source": "50", 823 | "target": "2" 824 | }, 825 | { 826 | "source": "51", 827 | "target": "2" 828 | }, 829 | { 830 | "source": "52", 831 | "target": "2" 832 | }, 833 | { 834 | "source": "53", 835 | "target": "2" 836 | }, 837 | { 838 | "source": "54", 839 | "target": "2" 840 | }, 841 | { 842 | "source": "7", 843 | "target": "3" 844 | }, 845 | { 846 | "source": "12", 847 | "target": "3" 848 | }, 849 | { 850 | "source": "13", 851 | "target": "3" 852 | }, 853 | { 854 | "source": "23", 855 | "target": "3" 856 | }, 857 | { 858 | "source": "52", 859 | "target": "3" 860 | }, 861 | { 862 | "source": "55", 863 | "target": "3" 864 | }, 865 | { 866 | "source": "56", 867 | "target": "3" 868 | }, 869 | { 870 | "source": "57", 871 | "target": "3" 872 | }, 873 | { 874 | "source": "58", 875 | "target": "3" 876 | }, 877 | { 878 | "source": "59", 879 | "target": "3" 880 | }, 881 | { 882 | "source": "60", 883 | "target": "3" 884 | }, 885 | { 886 | "source": "61", 887 | "target": "3" 888 | }, 889 | { 890 | "source": "62", 891 | "target": "3" 892 | }, 893 | { 894 | "source": "63", 895 | "target": "3" 896 | }, 897 | { 898 | "source": "14", 899 | "target": "4" 900 | }, 901 | { 902 | "source": "24", 903 | "target": "4" 904 | }, 905 | { 906 | "source": "25", 907 | "target": "4" 908 | }, 909 | { 910 | "source": "30", 911 | "target": "4" 912 | }, 913 | { 914 | "source": "31", 915 | "target": "4" 916 | }, 917 | { 918 | "source": "57", 919 | "target": "4" 920 | }, 921 | { 922 | "source": "58", 923 | "target": "4" 924 | }, 925 | { 926 | "source": "64", 927 | "target": "4" 928 | }, 929 | { 930 | "source": "65", 931 | "target": "4" 932 | }, 933 | { 934 | "source": "66", 935 | "target": "4" 936 | }, 937 | { 938 | "source": "62", 939 | "target": "4" 940 | }, 941 | { 942 | "source": "63", 943 | "target": "4" 944 | }, 945 | { 946 | "source": "15", 947 | "target": "5" 948 | }, 949 | { 950 | "source": "26", 951 | "target": "5" 952 | }, 953 | { 954 | "source": "27", 955 | "target": "5" 956 | }, 957 | { 958 | "source": "17", 959 | "target": "5" 960 | }, 961 | { 962 | "source": "32", 963 | "target": "5" 964 | }, 965 | { 966 | "source": "67", 967 | "target": "5" 968 | }, 969 | { 970 | "source": "54", 971 | "target": "5" 972 | }, 973 | { 974 | "source": "68", 975 | "target": "5" 976 | }, 977 | { 978 | "source": "69", 979 | "target": "5" 980 | }, 981 | { 982 | "source": "70", 983 | "target": "5" 984 | }, 985 | { 986 | "source": "71", 987 | "target": "5" 988 | }, 989 | { 990 | "source": "16", 991 | "target": "6" 992 | }, 993 | { 994 | "source": "28", 995 | "target": "6" 996 | }, 997 | { 998 | "source": "33", 999 | "target": "6" 1000 | }, 1001 | { 1002 | "source": "34", 1003 | "target": "6" 1004 | }, 1005 | { 1006 | "source": "72", 1007 | "target": "6" 1008 | }, 1009 | { 1010 | "source": "73", 1011 | "target": "6" 1012 | }, 1013 | { 1014 | "source": "69", 1015 | "target": "6" 1016 | }, 1017 | { 1018 | "source": "74", 1019 | "target": "6" 1020 | }, 1021 | { 1022 | "source": "75", 1023 | "target": "6" 1024 | } 1025 | ], 1026 | "categories": [ 1027 | { 1028 | "name": "玄幻" 1029 | }, 1030 | { 1031 | "name": "都市" 1032 | }, 1033 | { 1034 | "name": "导演" 1035 | }, 1036 | { 1037 | "name": "编剧" 1038 | }, 1039 | { 1040 | "name": "制片人" 1041 | }, 1042 | { 1043 | "name": "演员" 1044 | } 1045 | ] 1046 | } -------------------------------------------------------------------------------- /src/frontend/public/rawdata_1.0.2.json: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": [ 3 | { 4 | "id": "0", 5 | "name": "原来你还在这里", 6 | "symbolSize": 50, 7 | "x": -87.93029, 8 | "y": -6.8120565, 9 | "value": 100, 10 | "category": 1 11 | }, 12 | { 13 | "id": "1", 14 | "name": "无心法师", 15 | "symbolSize": 50, 16 | "x": -18.08344, 17 | "y": 10.8853, 18 | "value": 100, 19 | "category": 0 20 | }, 21 | { 22 | "id": "2", 23 | "name": "仙剑奇侠传三", 24 | "symbolSize": 50, 25 | "x": -28.76357, 26 | "y": -2.29176, 27 | "value": 100, 28 | "category": 0 29 | }, 30 | { 31 | "id": "3", 32 | "name": "三生三世十里桃花", 33 | "symbolSize": 50, 34 | "x": 12.82404, 35 | "y": 5.26283, 36 | "value": 100, 37 | "category": 0 38 | }, 39 | { 40 | "id": "4", 41 | "name": "三生三世枕上书", 42 | "symbolSize": 50, 43 | "x": -39.30386, 44 | "y": 29.06424, 45 | "value": 100, 46 | "category": 0 47 | }, 48 | { 49 | "id": "5", 50 | "name": "何以笙箫默", 51 | "symbolSize": 50, 52 | "x": -117.26337, 53 | "y": -16.03506, 54 | "value": 100, 55 | "category": 1 56 | }, 57 | { 58 | "id": "6", 59 | "name": "三十而已", 60 | "symbolSize": 50, 61 | "x": -32.6012, 62 | "y": -45.16974, 63 | "value": 100, 64 | "category": 1 65 | }, 66 | { 67 | "id": "7", 68 | "name": "林玉芬", 69 | "symbolSize": 15, 70 | "x": -382.69568, 71 | "y": 475.09113, 72 | "value": 10, 73 | "category": 2 74 | }, 75 | { 76 | "id": "8", 77 | "name": "高林豹", 78 | "symbolSize": 15, 79 | "x": -320.384, 80 | "y": 387.17325, 81 | "value": 10, 82 | "category": 2 83 | }, 84 | { 85 | "id": "9", 86 | "name": "李国立", 87 | "symbolSize": 15, 88 | "x": -344.39832, 89 | "y": 451.16772, 90 | "value": 10, 91 | "category": 2 92 | }, 93 | { 94 | "id": "10", 95 | "name": "梁胜权", 96 | "symbolSize": 15, 97 | "x": -89.34107, 98 | "y": 234.56128, 99 | "value": 10, 100 | "category": 2 101 | }, 102 | { 103 | "id": "11", 104 | "name": "黄俊文", 105 | "symbolSize": 15, 106 | "x": -100.93029, 107 | "y": -26.8120565, 108 | "value": 10, 109 | "category": 2 110 | }, 111 | { 112 | "id": "12", 113 | "name": "余翠华", 114 | "symbolSize": 15, 115 | "x": -339.77908, 116 | "y": -184.69139, 117 | "value": 10, 118 | "category": 2 119 | }, 120 | { 121 | "id": "13", 122 | "name": "任海涛", 123 | "symbolSize": 15, 124 | "x": -194.31313, 125 | "y": 178.55301, 126 | "value": 10, 127 | "category": 2 128 | }, 129 | { 130 | "id": "14", 131 | "name": "杨玄", 132 | "symbolSize": 15, 133 | "x": -158.05168, 134 | "y": 201.99768, 135 | "value": 10, 136 | "category": 2 137 | }, 138 | { 139 | "id": "15", 140 | "name": "刘俊杰", 141 | "symbolSize": 15, 142 | "x": -127.701546, 143 | "y": 242.55057, 144 | "value": 10, 145 | "category": 2 146 | }, 147 | { 148 | "id": "16", 149 | "name": "张晓波", 150 | "symbolSize": 15, 151 | "x": -385.2226, 152 | "y": -393.5572, 153 | "value": 10, 154 | "category": 2 155 | }, 156 | { 157 | "id": "17", 158 | "name": "金国栋", 159 | "symbolSize": 15, 160 | "x": -516.55884, 161 | "y": -393.98975, 162 | "value": 10, 163 | "category": 3 164 | }, 165 | { 166 | "id": "18", 167 | "name": "徐子沅", 168 | "symbolSize": 15, 169 | "x": -464.79382, 170 | "y": -493.57944, 171 | "value": 10, 172 | "category": 3 173 | }, 174 | { 175 | "id": "19", 176 | "name": "肖志瑶", 177 | "symbolSize": 15, 178 | "x": -515.1624, 179 | "y": -456.9891, 180 | "value": 10, 181 | "category": 3 182 | }, 183 | { 184 | "id": "20", 185 | "name": "李楠", 186 | "symbolSize": 15, 187 | "x": -408.12122, 188 | "y": -464.5048, 189 | "value": 10, 190 | "category": 3 191 | }, 192 | { 193 | "id": "21", 194 | "name": "方羌羌", 195 | "symbolSize": 15, 196 | "x": -456.44113, 197 | "y": -425.13303, 198 | "value": 10, 199 | "category": 3 200 | }, 201 | { 202 | "id": "22", 203 | "name": "邓紫珊", 204 | "symbolSize": 15, 205 | "x": -459.1107, 206 | "y": -362.5133, 207 | "value": 10, 208 | "category": 3 209 | }, 210 | { 211 | "id": "23", 212 | "name": "弘伙", 213 | "symbolSize": 15, 214 | "x": -313.42786, 215 | "y": -289.44803, 216 | "value": 10, 217 | "category": 3 218 | }, 219 | { 220 | "id": "24", 221 | "name": "梁振华", 222 | "symbolSize": 15, 223 | "x": 4.6313396, 224 | "y": -273.8517, 225 | "value": 10, 226 | "category": 3 227 | }, 228 | { 229 | "id": "25", 230 | "name": "胡雅婷", 231 | "symbolSize": 15, 232 | "x": 82.80825, 233 | "y": -203.1144, 234 | "value": 10, 235 | "category": 3 236 | }, 237 | { 238 | "id": "26", 239 | "name": "顾漫", 240 | "symbolSize": 15, 241 | "x": 78.64646, 242 | "y": -31.512747, 243 | "value": 10, 244 | "category": 3 245 | }, 246 | { 247 | "id": "27", 248 | "name": "墨宝非宝", 249 | "symbolSize": 15, 250 | "x": -81.46074, 251 | "y": -204.20204, 252 | "value": 10, 253 | "category": 3 254 | }, 255 | { 256 | "id": "28", 257 | "name": "张英姬", 258 | "symbolSize": 15, 259 | "x": -225.73984, 260 | "y": 82.41631, 261 | "value": 10, 262 | "category": 3 263 | }, 264 | { 265 | "id": "29", 266 | "name": "蔡艺侬", 267 | "symbolSize": 15, 268 | "x": -385.6842, 269 | "y": -20.206686, 270 | "value": 10, 271 | "category": 4 272 | }, 273 | { 274 | "id": "30", 275 | "name": "赵洁", 276 | "symbolSize": 15, 277 | "x": -403.92447, 278 | "y": -197.69823, 279 | "value": 10, 280 | "category": 4 281 | }, 282 | { 283 | "id": "31", 284 | "name": "高琛", 285 | "symbolSize": 15, 286 | "x": -281.4253, 287 | "y": -158.45137, 288 | "value": 10, 289 | "category": 4 290 | }, 291 | { 292 | "id": "32", 293 | "name": "房迎", 294 | "symbolSize": 15, 295 | "x": -122.41348, 296 | "y": 210.37503, 297 | "value": 10, 298 | "category": 4 299 | }, 300 | { 301 | "id": "33", 302 | "name": "陈菲", 303 | "symbolSize": 15, 304 | "x": -234.6001, 305 | "y": -113.15067, 306 | "value": 10, 307 | "category": 4 308 | }, 309 | { 310 | "id": "34", 311 | "name": "徐晓鸥", 312 | "symbolSize": 15, 313 | "x": -387.84915, 314 | "y": 58.7059, 315 | "value": 10, 316 | "category": 4 317 | }, 318 | { 319 | "id": "35", 320 | "name": "杨子姗", 321 | "symbolSize": 15, 322 | "x": -338.2307, 323 | "y": 87.48405, 324 | "value": 10, 325 | "category": 5 326 | }, 327 | { 328 | "id": "36", 329 | "name": "韩东君", 330 | "symbolSize": 15, 331 | "x": -453.26874, 332 | "y": 58.94648, 333 | "value": 10, 334 | "category": 5 335 | }, 336 | { 337 | "id": "37", 338 | "name": "李程彬", 339 | "symbolSize": 15, 340 | "x": -386.44904, 341 | "y": 140.05937, 342 | "value": 10, 343 | "category": 5 344 | }, 345 | { 346 | "id": "38", 347 | "name": "苏青", 348 | "symbolSize": 15, 349 | "x": -446.7876, 350 | "y": 123.38005, 351 | "value": 10, 352 | "category": 5 353 | }, 354 | { 355 | "id": "39", 356 | "name": "蓝盈莹", 357 | "symbolSize": 15, 358 | "x": 336.49738, 359 | "y": -269.55914, 360 | "value": 10, 361 | "category": 5 362 | }, 363 | { 364 | "id": "40", 365 | "name": "檀健次", 366 | "symbolSize": 15, 367 | "x": 29.187843, 368 | "y": -460.13132, 369 | "value": 10, 370 | "category": 5 371 | }, 372 | { 373 | "id": "41", 374 | "name": "温心", 375 | "symbolSize": 15, 376 | "x": 238.36697, 377 | "y": -210.00926, 378 | "value": 10, 379 | "category": 5 380 | }, 381 | { 382 | "id": "42", 383 | "name": "李兰迪", 384 | "symbolSize": 15, 385 | "x": 189.69513, 386 | "y": -346.50662, 387 | "value": 10, 388 | "category": 5 389 | }, 390 | { 391 | "id": "43", 392 | "name": "高圣远", 393 | "symbolSize": 15, 394 | "x": -187.00418, 395 | "y": -145.02663, 396 | "value": 10, 397 | "category": 5 398 | }, 399 | { 400 | "id": "44", 401 | "name": "胡先煦", 402 | "symbolSize": 15, 403 | "x": -252.99521, 404 | "y": 129.87549, 405 | "value": 10, 406 | "category": 5 407 | }, 408 | { 409 | "id": "45", 410 | "name": "金晨", 411 | "symbolSize": 15, 412 | "x": -296.07935, 413 | "y": 163.11964, 414 | "value": 10, 415 | "category": 5 416 | }, 417 | { 418 | "id": "46", 419 | "name": "陈瑶", 420 | "symbolSize": 15, 421 | "x": 550.3201, 422 | "y": 522.4031, 423 | "value": 10, 424 | "category": 5 425 | }, 426 | { 427 | "id": "47", 428 | "name": "张若昀", 429 | "symbolSize": 15, 430 | "x": 488.13535, 431 | "y": 356.8573, 432 | "value": 10, 433 | "category": 5 434 | }, 435 | { 436 | "id": "48", 437 | "name": "王彦霖", 438 | "symbolSize": 15, 439 | "x": 387.89572, 440 | "y": 110.462326, 441 | "value": 10, 442 | "category": 5 443 | }, 444 | { 445 | "id": "49", 446 | "name": "Mike", 447 | "symbolSize": 15, 448 | "x": 126.4831, 449 | "y": 68.10622, 450 | "value": 10, 451 | "category": 5 452 | }, 453 | { 454 | "id": "50", 455 | "name": "胡歌", 456 | "symbolSize": 15, 457 | "x": 127.07365, 458 | "y": -113.05923, 459 | "value": 10, 460 | "category": 5 461 | }, 462 | { 463 | "id": "51", 464 | "name": "霍建华", 465 | "symbolSize": 15, 466 | "x": 162.63559, 467 | "y": 117.6565, 468 | "value": 10, 469 | "category": 5 470 | }, 471 | { 472 | "id": "52", 473 | "name": "杨幂", 474 | "symbolSize": 15, 475 | "x": 353.66415, 476 | "y": -205.89165, 477 | "value": 10, 478 | "category": 5 479 | }, 480 | { 481 | "id": "53", 482 | "name": "刘诗诗", 483 | "symbolSize": 15, 484 | "x": 165.43939, 485 | "y": 339.7736, 486 | "value": 10, 487 | "category": 5 488 | }, 489 | { 490 | "id": "54", 491 | "name": "唐嫣", 492 | "symbolSize": 15, 493 | "x": 137.69348, 494 | "y": 196.1069, 495 | "value": 10, 496 | "category": 5 497 | }, 498 | { 499 | "id": "55", 500 | "name": "赵又廷", 501 | "symbolSize": 15, 502 | "x": 206.44687, 503 | "y": -13.805411, 504 | "value": 10, 505 | "category": 5 506 | }, 507 | { 508 | "id": "56", 509 | "name": "张智尧", 510 | "symbolSize": 15, 511 | "x": 194.82993, 512 | "y": 224.78036, 513 | "value": 10, 514 | "category": 5 515 | }, 516 | { 517 | "id": "57", 518 | "name": "迪丽热巴", 519 | "symbolSize": 15, 520 | "x": 597.6618, 521 | "y": 135.18481, 522 | "value": 10, 523 | "category": 5 524 | }, 525 | { 526 | "id": "58", 527 | "name": "高伟光", 528 | "symbolSize": 15, 529 | "x": 355.78366, 530 | "y": -74.882454, 531 | "value": 10, 532 | "category": 5 533 | }, 534 | { 535 | "id": "59", 536 | "name": "黄梦莹", 537 | "symbolSize": 15, 538 | "x": 515.2961, 539 | "y": -46.167564, 540 | "value": 10, 541 | "category": 5 542 | }, 543 | { 544 | "id": "60", 545 | "name": "张彬彬", 546 | "symbolSize": 15, 547 | "x": 614.29285, 548 | "y": -69.3104, 549 | "value": 10, 550 | "category": 5 551 | }, 552 | { 553 | "id": "61", 554 | "name": "于朦胧", 555 | "symbolSize": 15, 556 | "x": 550.1917, 557 | "y": -128.17537, 558 | "value": 10, 559 | "category": 5 560 | }, 561 | { 562 | "id": "62", 563 | "name": "刘芮麟", 564 | "symbolSize": 15, 565 | "x": 436.17184, 566 | "y": -12.7286825, 567 | "value": 10, 568 | "category": 5 569 | }, 570 | { 571 | "id": "63", 572 | "name": "王骁", 573 | "symbolSize": 15, 574 | "x": 602.55225, 575 | "y": 16.421427, 576 | "value": 10, 577 | "category": 5 578 | }, 579 | { 580 | "id": "64", 581 | "name": "陈楚河", 582 | "symbolSize": 15, 583 | "x": 455.81955, 584 | "y": -115.45826, 585 | "value": 10, 586 | "category": 5 587 | }, 588 | { 589 | "id": "65", 590 | "name": "郭品超", 591 | "symbolSize": 15, 592 | "x": 516.40784, 593 | "y": 47.242233, 594 | "value": 10, 595 | "category": 5 596 | }, 597 | { 598 | "id": "66", 599 | "name": "刘玥霏", 600 | "symbolSize": 15, 601 | "x": 646.4313, 602 | "y": -151.06331, 603 | "value": 10, 604 | "category": 5 605 | }, 606 | { 607 | "id": "67", 608 | "name": "钟汉良", 609 | "symbolSize": 15, 610 | "x": 668.9568, 611 | "y": 204.65488, 612 | "value": 10, 613 | "category": 5 614 | }, 615 | { 616 | "id": "68", 617 | "name": "谭凯", 618 | "symbolSize": 15, 619 | "x": 78.4799, 620 | "y": -347.15146, 621 | "value": 10, 622 | "category": 5 623 | }, 624 | { 625 | "id": "69", 626 | "name": "杨玏", 627 | "symbolSize": 15, 628 | "x": 150.35959, 629 | "y": -298.50797, 630 | "value": 10, 631 | "category": 5 632 | }, 633 | { 634 | "id": "70", 635 | "name": "菅纫姿", 636 | "symbolSize": 15, 637 | "x": 137.3717, 638 | "y": -410.2809, 639 | "value": 10, 640 | "category": 5 641 | }, 642 | { 643 | "id": "71", 644 | "name": "米露", 645 | "symbolSize": 15, 646 | "x": 234.87747, 647 | "y": -400.85983, 648 | "value": 10, 649 | "category": 5 650 | }, 651 | { 652 | "id": "72", 653 | "name": "江疏影", 654 | "symbolSize": 15, 655 | "x": 40.942253, 656 | "y": 113.78272, 657 | "value": 10, 658 | "category": 5 659 | }, 660 | { 661 | "id": "73", 662 | "name": "童瑶", 663 | "symbolSize": 15, 664 | "x": 437.939, 665 | "y": 291.58234, 666 | "value": 10, 667 | "category": 5 668 | }, 669 | { 670 | "id": "74", 671 | "name": "毛晓彤", 672 | "symbolSize": 15, 673 | "x": 466.04922, 674 | "y": 283.3606, 675 | "value": 10, 676 | "category": 5 677 | }, 678 | { 679 | "id": "75", 680 | "name": "李泽锋", 681 | "symbolSize": 15, 682 | "x": 238.79364, 683 | "y": -314.06345, 684 | "value": 10, 685 | "category": 5 686 | } 687 | ], 688 | "links": [ 689 | { 690 | "source": "7", 691 | "target": "0" 692 | }, 693 | { 694 | "source": "17", 695 | "target": "0" 696 | }, 697 | { 698 | "source": "29", 699 | "target": "0" 700 | }, 701 | { 702 | "source": "35", 703 | "target": "0" 704 | }, 705 | { 706 | "source": "36", 707 | "target": "0" 708 | }, 709 | { 710 | "source": "37", 711 | "target": "0" 712 | }, 713 | { 714 | "source": "38", 715 | "target": "0" 716 | }, 717 | { 718 | "source": "39", 719 | "target": "0" 720 | }, 721 | { 722 | "source": "40", 723 | "target": "0" 724 | }, 725 | { 726 | "source": "41", 727 | "target": "0" 728 | }, 729 | { 730 | "source": "42", 731 | "target": "0" 732 | }, 733 | { 734 | "source": "43", 735 | "target": "0" 736 | }, 737 | { 738 | "source": "44", 739 | "target": "0" 740 | }, 741 | { 742 | "source": "7", 743 | "target": "1" 744 | }, 745 | { 746 | "source": "8", 747 | "target": "1" 748 | }, 749 | { 750 | "source": "9", 751 | "target": "1" 752 | }, 753 | { 754 | "source": "18", 755 | "target": "1" 756 | }, 757 | { 758 | "source": "19", 759 | "target": "1" 760 | }, 761 | { 762 | "source": "20", 763 | "target": "1" 764 | }, 765 | { 766 | "source": "21", 767 | "target": "1" 768 | }, 769 | { 770 | "source": "29", 771 | "target": "1" 772 | }, 773 | { 774 | "source": "36", 775 | "target": "1" 776 | }, 777 | { 778 | "source": "45", 779 | "target": "1" 780 | }, 781 | { 782 | "source": "46", 783 | "target": "1" 784 | }, 785 | { 786 | "source": "47", 787 | "target": "1" 788 | }, 789 | { 790 | "source": "48", 791 | "target": "1" 792 | }, 793 | { 794 | "source": "49", 795 | "target": "1" 796 | }, 797 | { 798 | "source": "9", 799 | "target": "2" 800 | }, 801 | { 802 | "source": "10", 803 | "target": "2" 804 | }, 805 | { 806 | "source": "7", 807 | "target": "2" 808 | }, 809 | { 810 | "source": "11", 811 | "target": "2" 812 | }, 813 | { 814 | "source": "22", 815 | "target": "2" 816 | }, 817 | { 818 | "source": "29", 819 | "target": "2" 820 | }, 821 | { 822 | "source": "50", 823 | "target": "2" 824 | }, 825 | { 826 | "source": "51", 827 | "target": "2" 828 | }, 829 | { 830 | "source": "52", 831 | "target": "2" 832 | }, 833 | { 834 | "source": "53", 835 | "target": "2" 836 | }, 837 | { 838 | "source": "54", 839 | "target": "2" 840 | }, 841 | { 842 | "source": "7", 843 | "target": "3" 844 | }, 845 | { 846 | "source": "12", 847 | "target": "3" 848 | }, 849 | { 850 | "source": "13", 851 | "target": "3" 852 | }, 853 | { 854 | "source": "23", 855 | "target": "3" 856 | }, 857 | { 858 | "source": "52", 859 | "target": "3" 860 | }, 861 | { 862 | "source": "55", 863 | "target": "3" 864 | }, 865 | { 866 | "source": "56", 867 | "target": "3" 868 | }, 869 | { 870 | "source": "57", 871 | "target": "3" 872 | }, 873 | { 874 | "source": "58", 875 | "target": "3" 876 | }, 877 | { 878 | "source": "59", 879 | "target": "3" 880 | }, 881 | { 882 | "source": "60", 883 | "target": "3" 884 | }, 885 | { 886 | "source": "61", 887 | "target": "3" 888 | }, 889 | { 890 | "source": "62", 891 | "target": "3" 892 | }, 893 | { 894 | "source": "63", 895 | "target": "3" 896 | }, 897 | { 898 | "source": "14", 899 | "target": "4" 900 | }, 901 | { 902 | "source": "24", 903 | "target": "4" 904 | }, 905 | { 906 | "source": "25", 907 | "target": "4" 908 | }, 909 | { 910 | "source": "30", 911 | "target": "4" 912 | }, 913 | { 914 | "source": "31", 915 | "target": "4" 916 | }, 917 | { 918 | "source": "57", 919 | "target": "4" 920 | }, 921 | { 922 | "source": "58", 923 | "target": "4" 924 | }, 925 | { 926 | "source": "64", 927 | "target": "4" 928 | }, 929 | { 930 | "source": "65", 931 | "target": "4" 932 | }, 933 | { 934 | "source": "66", 935 | "target": "4" 936 | }, 937 | { 938 | "source": "62", 939 | "target": "4" 940 | }, 941 | { 942 | "source": "63", 943 | "target": "4" 944 | }, 945 | { 946 | "source": "15", 947 | "target": "5" 948 | }, 949 | { 950 | "source": "26", 951 | "target": "5" 952 | }, 953 | { 954 | "source": "27", 955 | "target": "5" 956 | }, 957 | { 958 | "source": "17", 959 | "target": "5" 960 | }, 961 | { 962 | "source": "32", 963 | "target": "5" 964 | }, 965 | { 966 | "source": "67", 967 | "target": "5" 968 | }, 969 | { 970 | "source": "54", 971 | "target": "5" 972 | }, 973 | { 974 | "source": "68", 975 | "target": "5" 976 | }, 977 | { 978 | "source": "69", 979 | "target": "5" 980 | }, 981 | { 982 | "source": "70", 983 | "target": "5" 984 | }, 985 | { 986 | "source": "71", 987 | "target": "5" 988 | }, 989 | { 990 | "source": "16", 991 | "target": "6" 992 | }, 993 | { 994 | "source": "28", 995 | "target": "6" 996 | }, 997 | { 998 | "source": "33", 999 | "target": "6" 1000 | }, 1001 | { 1002 | "source": "34", 1003 | "target": "6" 1004 | }, 1005 | { 1006 | "source": "72", 1007 | "target": "6" 1008 | }, 1009 | { 1010 | "source": "73", 1011 | "target": "6" 1012 | }, 1013 | { 1014 | "source": "69", 1015 | "target": "6" 1016 | }, 1017 | { 1018 | "source": "74", 1019 | "target": "6" 1020 | }, 1021 | { 1022 | "source": "75", 1023 | "target": "6" 1024 | } 1025 | ], 1026 | "categories": [ 1027 | { 1028 | "name": "玄幻" 1029 | }, 1030 | { 1031 | "name": "都市" 1032 | }, 1033 | { 1034 | "name": "导演" 1035 | }, 1036 | { 1037 | "name": "编剧" 1038 | }, 1039 | { 1040 | "name": "制片人" 1041 | }, 1042 | { 1043 | "name": "演员" 1044 | } 1045 | ] 1046 | } -------------------------------------------------------------------------------- /src/frontend/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /src/frontend/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/frontend/src/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import "bootstrap/dist/css/bootstrap.min.css"; 4 | import "shards-ui/dist/css/shards.min.css" 5 | import MainNavbar from './MainNavBar'; 6 | import MainContent from './MainContent'; 7 | 8 | function App() { 9 | return ( 10 |
11 | 12 | 13 |
14 | ); 15 | } 16 | 17 | export default App; 18 | -------------------------------------------------------------------------------- /src/frontend/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | import App from './App'; 4 | 5 | test('renders learn react link', () => { 6 | const { getByText } = render(); 7 | const linkElement = getByText(/learn react/i); 8 | expect(linkElement).toBeInTheDocument(); 9 | }); 10 | -------------------------------------------------------------------------------- /src/frontend/src/MainContent.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { 3 | Alert, 4 | ButtonToolbar, 5 | ButtonGroup, 6 | Card, 7 | CardBody, 8 | CardTitle, 9 | Button, 10 | Form, 11 | FormSelect, 12 | FormGroup, 13 | Container, 14 | Row, 15 | Col, 16 | FormCheckbox, 17 | } from "shards-react"; 18 | import axios from "axios"; 19 | import jwgl_has_data from "./data/jwgl_has_data.json"; 20 | import jwgl from "./data/jwgl.json"; 21 | 22 | const specialDate = [ 23 | "2020-10-04", 24 | "2020-10-10", 25 | "2020-10-17", 26 | "2020-10-24", 27 | "2020-11-07", 28 | ].map((date) => new Date(date).toDateString()); 29 | 30 | function checkSpecialDate() { 31 | const today = new Date(); 32 | return specialDate.indexOf(today.toDateString()); 33 | } 34 | 35 | function getDateDiff() { 36 | const date = new Date(); 37 | const startDate = new Date("2022-02-28"); 38 | startDate.setTime(startDate.getTime() + date.getTimezoneOffset() * 60 * 1000); 39 | return Math.max(0, Math.floor((date - startDate) / (24 * 3600 * 1000))); 40 | } 41 | 42 | function getTime() { 43 | const array = [ 44 | 845, 935, 1035, 1125, 1215, 1345, 1435, 1530, 1625, 1720, 1810, 1915, 2005, 45 | 2055, 46 | ]; 47 | const now = new Date(); 48 | const hour = now.getHours(); 49 | const minutes = now.getMinutes(); 50 | const timeOfDay = hour * 100 + minutes; 51 | for (var i = 0; i < array.length; i++) { 52 | if (timeOfDay < array[i]) { 53 | return i + 1; 54 | } 55 | } 56 | return 1; 57 | } 58 | 59 | function getEndTime(startTime) { 60 | if (startTime < 5) { 61 | return 5; 62 | } 63 | if (startTime < 9) { 64 | return 9; 65 | } 66 | if (startTime < 11) { 67 | return 11; 68 | } 69 | return 14; 70 | } 71 | 72 | function getDefaultSelectedArray() { 73 | const startTime = getTime(); 74 | const endTime = getEndTime(startTime); 75 | var selectedArray = Array(15).fill(false); 76 | for (var i = 1; i < 15; i += 1) { 77 | if (i >= startTime && i <= endTime) { 78 | selectedArray[i] = true; 79 | } 80 | } 81 | return selectedArray; 82 | } 83 | 84 | function getWeek(dateDiff) { 85 | const index = checkSpecialDate(); 86 | if (index !== -1) { 87 | if (index < 5) { 88 | return 17; 89 | } 90 | return 18; 91 | } 92 | return Math.floor(dateDiff / 7) + 1; 93 | } 94 | 95 | function getDay(dateDiff) { 96 | const index = checkSpecialDate(); 97 | if (index !== -1) { 98 | return (index % 5) + 1; 99 | } 100 | return Math.floor(dateDiff % 7) + 1; 101 | } 102 | 103 | function getRealWeek(dateDiff) { 104 | return Math.floor(dateDiff / 7) + 1; 105 | } 106 | 107 | function getRealDay(dateDiff) { 108 | return Math.floor(dateDiff % 7) + 1; 109 | } 110 | 111 | function getSingleResult(week, day, time) { 112 | let week_prefix = week < 10 ? "0" : ""; 113 | let time_prefix = time < 10 ? "0" : ""; 114 | let key = week_prefix + week + "." + day + "." + time_prefix + time; 115 | var s = new Set(); 116 | let result = jwgl[key]; 117 | //console.log(key); 118 | //console.log(result); 119 | for (const building in result) { 120 | result[building].forEach((room) => { 121 | let t = { 122 | "building": building, 123 | "name": room["name"], 124 | "function": room["function"], 125 | "seats": room["seats"], 126 | }; 127 | s.add(JSON.stringify(t)); 128 | }) 129 | } 130 | return s; 131 | } 132 | 133 | function intersection(setA, setB) { 134 | let _intersection = new Set() 135 | for (let elem of setB) { 136 | if (setA.has(elem)) { 137 | _intersection.add(elem) 138 | } 139 | } 140 | return _intersection 141 | } 142 | 143 | function compat(data) { 144 | var map = new Map(); 145 | for (let room of data) { 146 | let item = JSON.parse(room); 147 | let building = item["building"]; 148 | let info = { 149 | "name": item["name"], 150 | "function": item["function"], 151 | "seats": item["seats"], 152 | }; 153 | if (map.has(building)) { 154 | map.get(building).push(info); 155 | } else { 156 | map.set(building, [info]); 157 | } 158 | } 159 | var result = []; 160 | map.forEach((value, key) => { 161 | result.push({ 162 | "building": key, 163 | "classrooms": value, 164 | }); 165 | }) 166 | return result; 167 | } 168 | 169 | function getMultipleResult(week, day, times) { 170 | if (times.length === 0) { 171 | alert("请选择一个时间段"); 172 | } else if (times.length === 1) { 173 | return compat(getSingleResult(week, day, times[0])); 174 | } else { 175 | let result = getSingleResult(week, day, times[0]); 176 | for (let i = 1; i < times.length; i++) { 177 | result = intersection(result, getSingleResult(week, day, times[i])); 178 | } 179 | return compat(result); 180 | } 181 | } 182 | 183 | class MainContent extends React.Component { 184 | constructor(props) { 185 | super(props); 186 | const dateDiff = getDateDiff(); 187 | this.state = { 188 | jwgl_has_data: true, 189 | jwgl: checkSpecialDate() === -1 ? true : false, 190 | selected: getDefaultSelectedArray(), 191 | week: "" + getWeek(dateDiff), 192 | day: "" + getDay(dateDiff), 193 | realWeek: "" + getRealWeek(dateDiff), 194 | realDay: "" + getRealDay(dateDiff), 195 | time: "" + getTime(), 196 | result: [], 197 | }; 198 | 199 | this.setState({ jwgl_has_data: jwgl_has_data.has_data }); 200 | this.setState({ jwgl: jwgl_has_data.has_data }); 201 | 202 | this.setWeek = this.setWeek.bind(this); 203 | this.setDay = this.setDay.bind(this); 204 | this.setTime = this.setTime.bind(this); 205 | this.setSelect = this.setSelect.bind(this); 206 | this.rangeChecked = this.rangeChecked.bind(this); 207 | this.getNewResult = this.getNewResult.bind(this); 208 | this.renderButton = this.renderButton.bind(this); 209 | this.renderButtons = this.renderButtons.bind(this); 210 | this.renderButtonToolbar = this.renderButtonToolbar.bind(this); 211 | this.renderSingleUnit = this.renderSingleUnit.bind(this); 212 | this.renderSingleClassRoom = this.renderSingleClassRoom.bind(this); 213 | this.renderResult = this.renderResult.bind(this); 214 | } 215 | 216 | setWeek(value) { 217 | this.setState({ week: value }); 218 | } 219 | 220 | setDay(value) { 221 | this.setState({ day: value }); 222 | } 223 | 224 | setTime(value) { 225 | this.setState({ time: value }); 226 | } 227 | 228 | setSelect(i) { 229 | var sel = this.state.selected.slice(); 230 | sel[i] = !this.state.selected[i]; 231 | this.setState({ selected: sel }); 232 | } 233 | 234 | rangeChecked(jwgl) { 235 | if (this.state.jwgl_has_data) { 236 | this.setState({ jwgl: jwgl }); 237 | } 238 | const dateDiff = getDateDiff(); 239 | this.setWeek("" + getWeek(dateDiff)); 240 | this.setDay("" + getDay(dateDiff)); 241 | } 242 | 243 | getTimeString() { 244 | var time_string = ""; 245 | for (var i = 0; i < 15; i++) { 246 | if (this.state.selected[i]) { 247 | time_string += "&time=" + i; 248 | } 249 | } 250 | return time_string; 251 | } 252 | 253 | getTimes() { 254 | var result = [] 255 | for (var i = 0; i < 15; i++) { 256 | if (this.state.selected[i]) { 257 | result.push(i - 1); 258 | } 259 | } 260 | return result; 261 | } 262 | 263 | getNewResult() { 264 | if (!this.state.selected.reduce((a, b) => a || b)) { 265 | alert("请至少点选一个时间段"); 266 | } else { 267 | /* 268 | const prefix = this.state.jwgl 269 | ? "https://name1e5s.fun:6324/free_classrooms_jwgl?week=" 270 | : "https://name1e5s.fun:6324/free_classrooms?week=";*/ 271 | const week = this.state.jwgl ? this.state.realWeek : this.state.week; 272 | const day = this.state.day; 273 | //const url = prefix + week + "&day=" + day + this.getTimeString(); 274 | this.setState({ result: getMultipleResult(week, day - 1, this.getTimes()) }); 275 | /*axios 276 | .get(url) 277 | .then((res) => { 278 | this.setState({ result: res.data }); 279 | if (res.data.length === 0) { 280 | alert( 281 | "暂无空教室,试试课表/考表数据吧\nPS:教务系统的空教室信息每晚零点自动更新" 282 | ); 283 | } 284 | }) 285 | .catch((error) => { 286 | alert("网络故障\nPS:最近校园网不稳定,可以切换到流量后再试试"); 287 | });*/ 288 | } 289 | } 290 | 291 | renderButton(i) { 292 | if (i === 15) { 293 | return ( 294 | 297 | ); 298 | } 299 | return ( 300 | 311 | ); 312 | } 313 | 314 | renderButtons(start) { 315 | const buttons = []; 316 | for (var i = start; i < start + 5; i++) { 317 | buttons.push(this.renderButton(i)); 318 | } 319 | return buttons; 320 | } 321 | 322 | renderButtonToolbar() { 323 | return ( 324 | 325 | 326 | 327 | {this.renderButtons(1)} 328 | 329 | 330 | 331 | 332 | {this.renderButtons(6)} 333 | 334 | 335 | 336 | 337 | {this.renderButtons(11)} 338 | 339 | 340 | 341 | ); 342 | } 343 | 344 | renderSingleClassRoom(classroom) { 345 | return ( 346 | 347 | {classroom.name} 348 | {classroom.seats} 349 | 350 | ); 351 | } 352 | 353 | renderSingleUnit(unit) { 354 | return ( 355 | 356 | 357 | 358 | 359 | {unit.building} 360 | 361 | 362 | 363 | 364 | 365 | 366 | 369 | 372 | 373 | 374 | 375 | {unit.classrooms.map(this.renderSingleClassRoom)} 376 | 377 |
367 | 教室 368 | 370 | 座椅数 371 |
378 | 379 |
380 |
381 |
382 |
383 | 384 |
385 | ); 386 | } 387 | 388 | renderResult() { 389 | if (!this.state.result) { 390 | return <>; 391 | } 392 | return this.state.result.map(this.renderSingleUnit); 393 | } 394 | 395 | renderTime() { 396 | if (true) { 397 | return ( 398 | 399 | 400 | {this.renderButtonToolbar()} 401 | 402 | ); 403 | } 404 | return ( 405 | 406 | 407 | this.setTime(e.target.value)} 411 | > 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | ); 429 | } 430 | 431 | renderAlert() { 432 | if (!this.state.jwgl_has_data) { 433 | return ( 434 | 435 | 436 | 教务系统崩了 - 请使用课表数据 437 | 438 | 439 | ); 440 | } 441 | return <>; 442 | } 443 | 444 | render() { 445 | return ( 446 | 447 | 448 | {this.renderAlert()} 449 | 450 | 451 | 后端服务器因为没有备案被橄榄了,暂时先把数据存在前端,寒假重写摸了 452 | 453 | 454 | 455 | 456 | 457 |
458 | 459 | 460 | 461 | 462 | 471 | 480 | 481 | 482 | 483 | 484 | 485 | { 490 | if (true) { 491 | this.setWeek(e.target.value); 492 | } 493 | }} 494 | > 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | { 521 | this.setDay(e.target.value); 522 | }} 523 | > 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | {this.renderTime()} 534 |
535 | 538 |
539 |
540 |
541 |
542 | 543 |
544 | {this.renderResult()} 545 |
546 | ); 547 | } 548 | } 549 | 550 | export default MainContent; 551 | -------------------------------------------------------------------------------- /src/frontend/src/MainNavBar.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Navbar, NavbarBrand } from "shards-react"; 3 | 4 | const MainNavbar = () => { 5 | const title = "空闲教室查询" 6 | 7 | return ( 8 | 9 | {title} 10 | GitHub 11 | 12 | ); 13 | }; 14 | 15 | export default MainNavbar; -------------------------------------------------------------------------------- /src/frontend/src/data/jwgl_has_data.json: -------------------------------------------------------------------------------- 1 | {"has_data": true} -------------------------------------------------------------------------------- /src/frontend/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /src/frontend/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import * as serviceWorker from './serviceWorker'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root') 12 | ); 13 | 14 | // If you want your app to work offline and load faster, you can change 15 | // unregister() to register() below. Note this comes with some pitfalls. 16 | // Learn more about service workers: https://bit.ly/CRA-PWA 17 | serviceWorker.unregister(); 18 | -------------------------------------------------------------------------------- /src/frontend/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/frontend/src/serviceWorker.js: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read https://bit.ly/CRA-PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === 'localhost' || 15 | // [::1] is the IPv6 localhost address. 16 | window.location.hostname === '[::1]' || 17 | // 127.0.0.0/8 are considered localhost for IPv4. 18 | window.location.hostname.match( 19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 20 | ) 21 | ); 22 | 23 | export function register(config) { 24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 25 | // The URL constructor is available in all browsers that support SW. 26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); 27 | if (publicUrl.origin !== window.location.origin) { 28 | // Our service worker won't work if PUBLIC_URL is on a different origin 29 | // from what our page is served on. This might happen if a CDN is used to 30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 31 | return; 32 | } 33 | 34 | window.addEventListener('load', () => { 35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 36 | 37 | if (isLocalhost) { 38 | // This is running on localhost. Let's check if a service worker still exists or not. 39 | checkValidServiceWorker(swUrl, config); 40 | 41 | // Add some additional logging to localhost, pointing developers to the 42 | // service worker/PWA documentation. 43 | navigator.serviceWorker.ready.then(() => { 44 | console.log( 45 | 'This web app is being served cache-first by a service ' + 46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA' 47 | ); 48 | }); 49 | } else { 50 | // Is not localhost. Just register service worker 51 | registerValidSW(swUrl, config); 52 | } 53 | }); 54 | } 55 | } 56 | 57 | function registerValidSW(swUrl, config) { 58 | navigator.serviceWorker 59 | .register(swUrl) 60 | .then(registration => { 61 | registration.onupdatefound = () => { 62 | const installingWorker = registration.installing; 63 | if (installingWorker == null) { 64 | return; 65 | } 66 | installingWorker.onstatechange = () => { 67 | if (installingWorker.state === 'installed') { 68 | if (navigator.serviceWorker.controller) { 69 | // At this point, the updated precached content has been fetched, 70 | // but the previous service worker will still serve the older 71 | // content until all client tabs are closed. 72 | console.log( 73 | 'New content is available and will be used when all ' + 74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' 75 | ); 76 | 77 | // Execute callback 78 | if (config && config.onUpdate) { 79 | config.onUpdate(registration); 80 | } 81 | } else { 82 | // At this point, everything has been precached. 83 | // It's the perfect time to display a 84 | // "Content is cached for offline use." message. 85 | console.log('Content is cached for offline use.'); 86 | 87 | // Execute callback 88 | if (config && config.onSuccess) { 89 | config.onSuccess(registration); 90 | } 91 | } 92 | } 93 | }; 94 | }; 95 | }) 96 | .catch(error => { 97 | console.error('Error during service worker registration:', error); 98 | }); 99 | } 100 | 101 | function checkValidServiceWorker(swUrl, config) { 102 | // Check if the service worker can be found. If it can't reload the page. 103 | fetch(swUrl, { 104 | headers: { 'Service-Worker': 'script' }, 105 | }) 106 | .then(response => { 107 | // Ensure service worker exists, and that we really are getting a JS file. 108 | const contentType = response.headers.get('content-type'); 109 | if ( 110 | response.status === 404 || 111 | (contentType != null && contentType.indexOf('javascript') === -1) 112 | ) { 113 | // No service worker found. Probably a different app. Reload the page. 114 | navigator.serviceWorker.ready.then(registration => { 115 | registration.unregister().then(() => { 116 | window.location.reload(); 117 | }); 118 | }); 119 | } else { 120 | // Service worker found. Proceed as normal. 121 | registerValidSW(swUrl, config); 122 | } 123 | }) 124 | .catch(() => { 125 | console.log( 126 | 'No internet connection found. App is running in offline mode.' 127 | ); 128 | }); 129 | } 130 | 131 | export function unregister() { 132 | if ('serviceWorker' in navigator) { 133 | navigator.serviceWorker.ready 134 | .then(registration => { 135 | registration.unregister(); 136 | }) 137 | .catch(error => { 138 | console.error(error.message); 139 | }); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/frontend/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom/extend-expect'; 6 | -------------------------------------------------------------------------------- /src/utils/jwgl.py: -------------------------------------------------------------------------------- 1 | from bs4 import BeautifulSoup 2 | from collections import defaultdict 3 | import re 4 | from typing import List, Tuple 5 | import requests 6 | import datetime 7 | import json 8 | import time 9 | 10 | requests.packages.urllib3.disable_warnings() 11 | requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS += 'HIGH:!DH:!aNULL' 12 | try: 13 | requests.packages.urllib3.contrib.pyopenssl.DEFAULT_SSL_CIPHER_LIST += 'HIGH:!DH:!aNULL' 14 | except AttributeError: 15 | # no pyopenssl support used / needed / available 16 | pass 17 | 18 | ua = { 19 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 20 | 'Accept-Encoding': 'gzip, deflate, br', 21 | 'Accept-Language': 'zh-CN,zh;q=0.9', 22 | 'User-Agent': 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36', 23 | 'Host': 'jwxt.bupt.edu.cn', 24 | 'Origin': 'https://jwxt.bupt.edu.cn' 25 | } 26 | 27 | 28 | def encodepw(username, password): 29 | from base64 import b64encode 30 | return (b64encode(str.encode(username)) + b"%%%" + b64encode(str.encode(password))).decode() 31 | 32 | 33 | def get_text(username, password, week, day): 34 | url = "https://jwgl.bupt.edu.cn/jsxsd/" 35 | ua['Host'] = "jwgl.bupt.edu.cn" 36 | ua['Accept'] = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8," \ 37 | "application/signed-exchange;v=b3;q=0.9 " 38 | if 'Origin' in ua.keys(): 39 | del ua['Origin'] 40 | _ = requests.get(url=url, headers=ua, verify=False) # 获得登录页面 41 | url_auth = "https://jwgl.bupt.edu.cn/jsxsd/xk/LoginToXk" 42 | ua['Origin'] = "https://jwgl.bupt.edu.cn" 43 | data = { 44 | "userAccount": username, 45 | "userPassword": password, 46 | "encoded": encodepw(username, password) 47 | } 48 | s = requests.session() 49 | _ = s.post(url=url_auth, headers={"Referer": "https://jwgl.bupt.edu.cn/jsxsd/", 50 | "Origin": "https://jwgl.bupt.edu.cn", }, data=data, verify=False) 51 | s.headers.update({'Referer': "https://jwgl.bupt.edu.cn/jsxsd/framework/xsMain.jsp"}) 52 | if 'Origin' in ua.keys(): 53 | del ua['Origin'] 54 | class_data = { 55 | 'typewhere': 'jszq', 56 | 'xnxqh': '2021-2022-1', 57 | 'xqbh': '01', 58 | 'bjfh': '=', 59 | 'jszt': '5', 60 | 'zc': str(week), 61 | 'zc2': str(week), 62 | 'xq': str(day), 63 | 'xq2': str(day), 64 | 'kbjcmsid': '9475847A3F3033D1E05377B5030AA94D', 65 | } 66 | kb_html = s.post(url="https://jwgl.bupt.edu.cn/jsxsd/kbxx/jsjy_query2", headers=ua, data=class_data, verify=False) 67 | kb_html.encoding = "utf-8" 68 | ua['Origin'] = "https://jwgl.bupt.edu.cn" 69 | return kb_html.text 70 | 71 | 72 | def get_class(class_name: str) -> int: 73 | if class_name.startswith('图书馆'): 74 | return 0 75 | return int(class_name.split('-')[0]) 76 | 77 | 78 | def get_class_name(class_num: int) -> str: 79 | if class_num == 0: 80 | return '图书馆' 81 | if class_num == 1: 82 | return '教一楼' 83 | if class_num == 2: 84 | return '教二楼' 85 | if class_num == 3: 86 | return '教三楼' 87 | if class_num == 4: 88 | return '教四楼' 89 | 90 | 91 | def get_info(classroom: Tuple[str, int, str, List]): 92 | return { 93 | "name": classroom[0], 94 | "function": "多媒体教室(校本部)", 95 | "seats": classroom[1] 96 | } 97 | 98 | 99 | def generate_free_table(html: str) -> List[Tuple[str, int, str, List]]: 100 | bs = BeautifulSoup(html, features="html.parser") 101 | classrooms = bs.find_all('tr', {'onmouseover': 'this.style.cursor=\'hand\''}) 102 | schedule = [] 103 | for i in classrooms: 104 | temp = [] 105 | tds = i.find_all('td') 106 | info = tds[0].text.strip().split('|')[0].split('(') 107 | if info[0].startswith('虚拟'): 108 | continue 109 | name: str = info[0] 110 | seats = int(re.findall(r'(.*)/', info[1])[0]) 111 | for j in range(1, len(tds)): 112 | temp.append(tds[j].text.strip()) 113 | schedule.append((name, seats, get_class_name(get_class(name)), temp)) 114 | return schedule 115 | 116 | 117 | def generate_result(schedule, week, day): 118 | result = {} 119 | for i in range(14): 120 | free = defaultdict(list) 121 | for t in schedule: 122 | if len(t[3][i]) == 0: 123 | free[t[2]].append(get_info(t)) 124 | for _, v in free.items(): 125 | v.sort(key=lambda x: x['name']) 126 | result['%02d' % week + '.' + str(day - 1) + '.' + '%02d' % i] = free 127 | return result 128 | 129 | 130 | def get_result(name, password, week, day): 131 | schedule = generate_free_table(get_text(name, password, week, day)) 132 | return generate_result(schedule, week, day) 133 | 134 | 135 | def get_week_day(): 136 | diff = (datetime.datetime.now() - datetime.datetime(2021, 8, 30, 0, 0, 0)).days 137 | diff = max(diff, 0) 138 | return diff // 7 + 1, diff % 7 + 1 139 | 140 | 141 | if __name__ == '__main__': 142 | info = get_week_day() 143 | result = {} 144 | for i in range(7): 145 | t = get_result('__username__', '__password__', info[0], i + 1) 146 | result.update(t) 147 | time.sleep(0.5) 148 | with open("jwgl.json", mode='w', encoding='utf-8') as f: 149 | json.dump(result, f, indent=4, ensure_ascii=False) 150 | f.close() 151 | -------------------------------------------------------------------------------- /src/utils/parse_xls.py: -------------------------------------------------------------------------------- 1 | """将教务处的表格处理为可供后端调用的 json 文件""" 2 | from __future__ import annotations 3 | 4 | import argparse 5 | import json 6 | import re 7 | import xlrd 8 | 9 | from typing import List, Set, Dict, Tuple 10 | from collections import defaultdict 11 | 12 | 13 | class Classroom(object): 14 | def __init__(self, sheet: xlrd.sheet.Sheet, start_row: int): 15 | subtitle = sheet.row_values(start_row + 1)[1].split() 16 | self.name = subtitle[1][3:] 17 | self.function = subtitle[2][6:] 18 | self.building = subtitle[3][6:] 19 | self.seats = int(subtitle[4][4:]) 20 | self.schedule = self.generate_schedule(sheet, start_row) 21 | 22 | @staticmethod 23 | def generate_schedule(sheet: xlrd.sheet.Sheet, start_row: int) -> List[List[Set[int]]]: 24 | schedule = [] 25 | for i in range(14): 26 | schedule.append([]) 27 | current_row_value = sheet.row_values(start_row + 3 + i) 28 | for j in range(7): 29 | schedule[-1].append(Classroom.parse_single_cell(current_row_value[j + 1])) 30 | return schedule 31 | 32 | @staticmethod 33 | def parse_single_cell(cell: str) -> Set[int]: 34 | cell_data = set() 35 | busy_weeks = list(map(lambda x: x.strip(), re.findall(r'(.*)周\[\d*节]', cell))) 36 | for week_section in busy_weeks: 37 | weeks_list = week_section.split(',') 38 | for weeks in weeks_list: 39 | # 在本部的课表中,单双周基本上为 '1单周' 这种格式,我们将其视为课表的错误 40 | if weeks.endswith('单') or weeks.endswith('双'): 41 | weeks = weeks[:-1] 42 | week_range = weeks.split('-') 43 | if len(week_range) == 2: 44 | for i in range(int(week_range[0]), int(week_range[1]) + 1): 45 | cell_data.add(i) 46 | if len(week_range) == 1: 47 | cell_data.add(int(week_range[0])) 48 | return cell_data 49 | 50 | def merge_schedule(self, other: Classroom): 51 | for i in range(14): 52 | for j in range(7): 53 | self.schedule[i][j] = self.schedule[i][j].union(other.schedule[i][j]) 54 | 55 | def merge_tuple(self, other: Tuple[int, Tuple[int, int], Tuple[Tuple[int, int], int], str]): 56 | weeks = set() 57 | filtered = other[2][1] 58 | for i in range(other[2][0][0], other[2][0][1] + 1): 59 | if filtered == 0 or (filtered == 1 and i % 2 == 1) or (filtered == 2 and i % 2 == 0): 60 | weeks.add(i) 61 | for i in range(other[1][0], other[1][1] + 1): 62 | self.schedule[i - 1][other[0]] = self.schedule[i - 1][other[0]].union(weeks) 63 | 64 | def is_free(self, week: int, day: int, time: int) -> bool: 65 | return week not in self.schedule[time][day] 66 | 67 | def to_dict(self) -> Dict: 68 | dict_result = { 69 | 'name': self.name, 70 | 'function': self.function, 71 | 'building': self.building, 72 | 'seats': self.seats, 73 | 'schedule': [] 74 | } 75 | for i in range(14): 76 | dict_result['schedule'].append([]) 77 | for j in range(7): 78 | dict_result['schedule'][-1].append(list(self.schedule[i][j])) 79 | return dict_result 80 | 81 | def to_info_dict(self) -> Dict: 82 | return { 83 | 'name': self.name, 84 | 'function': self.function, 85 | 'seats': self.seats, 86 | } 87 | 88 | 89 | class Sheet(object): 90 | def __init__(self, file_name: str, sheet_name='Sheet1'): 91 | workbook = xlrd.open_workbook(file_name) 92 | self.sheet = workbook.sheet_by_index(0) 93 | self.iterator = -1 94 | 95 | def reset_iterator(self): 96 | self.iterator = -1 97 | 98 | def valid_row_index(self, row_index: int) -> bool: 99 | return row_index < self.sheet.nrows 100 | 101 | def find_next_classroom(self): 102 | self.iterator += 1 103 | while self.valid_row_index(self.iterator) \ 104 | and not self.sheet.row_values(self.iterator)[0].startswith('北京邮电大学'): 105 | self.iterator += 1 106 | return self.valid_row_index(self.iterator) 107 | 108 | def generate_single_classroom_info(self) -> Classroom: 109 | return Classroom(self.sheet, self.iterator) 110 | 111 | def generate_classrooms_info(self) -> List[Classroom]: 112 | classroom_list = [] 113 | while self.find_next_classroom(): 114 | classroom_list.append(self.generate_single_classroom_info()) 115 | self.reset_iterator() 116 | return classroom_list 117 | 118 | def generate_classrooms_info_dict(self): 119 | classroom_dict = {} 120 | while self.find_next_classroom(): 121 | info = self.generate_single_classroom_info() 122 | classroom_dict[info.name] = info 123 | self.reset_iterator() 124 | return classroom_dict 125 | 126 | 127 | def generate_graduate_schedule_list(graduate_sheet: List[str]) \ 128 | -> List[Tuple[int, Tuple[int, int], Tuple[Tuple[int, int], int], str]]: 129 | schedule_list = [] 130 | for file in graduate_sheet: 131 | workbook = xlrd.open_workbook(file) 132 | sheet = workbook.sheet_by_index(0) 133 | for i in range(1, sheet.nrows): 134 | temp = get_single_graduate_tuple(sheet.row_values(i)[7]) 135 | if temp: 136 | schedule_list.append(temp) 137 | return schedule_list 138 | 139 | 140 | def get_single_graduate_tuple(value) -> Tuple[int, Tuple[int, int], Tuple[Tuple[int, int], int], str] | None: 141 | if value.strip().startswith('参见') or value.strip().startswith('查看'): 142 | return None 143 | real_data = re.findall(r'^([^;]*)\((\d*-\d*)节\)\[(.*)]', value) 144 | if len(real_data) != 1 or len(real_data[0]) != 3: 145 | return None 146 | real_data = real_data[0] 147 | info = real_data[2].split(',') 148 | day = day_to_int(real_data[0]) 149 | graduate_cell = (day, time_to_tuple(real_data[1]), 150 | week_to_tuple(info[0]), location_to_classroom(info[-1])) 151 | if day == -1: 152 | return None 153 | return graduate_cell 154 | 155 | 156 | def day_to_int(day: str) -> int: 157 | if len(day) == 0: 158 | return -1 159 | s = '一二三四五六七' 160 | t = day[-1] 161 | for index, value in enumerate(s): 162 | if t == value: 163 | return index 164 | return -1 165 | 166 | 167 | def time_to_tuple(time: str) -> Tuple[int, int]: 168 | temp = list(map(int, time.split('-'))) 169 | return temp[0], temp[1] 170 | 171 | 172 | def week_to_tuple(week: str) -> Tuple[Tuple[int, int], int]: 173 | week_filter = 0 174 | week = week[:-1] 175 | if week.endswith('单'): 176 | week_filter = 1 177 | week = week[:-1] 178 | if week.endswith('双'): 179 | week_filter = 2 180 | week = week[:-1] 181 | for week_range in week.split('、'): 182 | week_range_list = list(map(int, week_range.split('-'))) 183 | if len(week_range_list) == 1: 184 | return (week_range_list[0], week_range_list[0]), week_filter 185 | return (week_range_list[0], week_range_list[1]), week_filter 186 | 187 | 188 | def location_to_classroom(location: str) -> str: 189 | return location[3:].replace('经-', '经管楼-') 190 | 191 | 192 | def get_classrooms(sheet_by_room: List[str], graduate_sheet: List[str]) -> List[Classroom]: 193 | if len(sheet_by_room) < 1: 194 | return [] 195 | if len(sheet_by_room) == 1: 196 | return Sheet(sheet_by_room[0]).generate_classrooms_info() 197 | all_classrooms = Sheet(sheet_by_room[0]).generate_classrooms_info_dict() 198 | cdr = sheet_by_room[1:] 199 | for sheet in cdr: 200 | classrooms = Sheet(sheet).generate_classrooms_info() 201 | for classroom in classrooms: 202 | if classroom.name in all_classrooms: 203 | all_classrooms[classroom.name].merge_schedule(classroom) 204 | else: 205 | all_classrooms[classroom.name] = classroom 206 | for t in generate_graduate_schedule_list(graduate_sheet): 207 | if t[-1] in all_classrooms: 208 | all_classrooms[t[-1]].merge_tuple(t) 209 | 210 | return list(all_classrooms.values()) 211 | 212 | 213 | def filter_classrooms(classrooms: List[Classroom], 214 | function_allow_list=None, 215 | name_deny_list=None) -> List[Classroom]: 216 | if function_allow_list is None: 217 | function_allow_list = [] 218 | if name_deny_list is None: 219 | name_deny_list = [] 220 | 221 | filtered_classrooms = list(filter(lambda x: not x.seats == 0, classrooms)) 222 | for prefix in function_allow_list: 223 | filtered_classrooms = list(filter(lambda x: x.function.startswith(prefix), filtered_classrooms)) 224 | for prefix in name_deny_list: 225 | filtered_classrooms = list(filter(lambda x: not x.name.startswith(prefix), filtered_classrooms)) 226 | return filtered_classrooms 227 | 228 | 229 | def get_classroom_dict(classrooms: List[Classroom]) -> Dict[str, List[Classroom]]: 230 | classroom_dict = defaultdict(list) 231 | for i in classrooms: 232 | classroom_dict[i.building].append(i) 233 | return classroom_dict 234 | 235 | 236 | def get_free_classroom_dict(classroom_dict: Dict[str, List[Classroom]]): 237 | free_classroom_dict = {} 238 | for week in range(1, 19): 239 | for day in range(7): 240 | for time in range(14): 241 | week_str = '%02d' % week 242 | day_str = '%d' % day 243 | time_str = '%02d' % time 244 | key = week_str + '.' + day_str + '.' + time_str 245 | value = {} 246 | for i in classroom_dict.keys(): 247 | temp = [] 248 | for j in classroom_dict[i]: 249 | if j.is_free(week, day, time): 250 | temp.append(j.to_info_dict()) 251 | temp.sort(key=lambda x: x['name']) 252 | if len(temp) > 0: 253 | value[i] = temp 254 | value_list = [] 255 | for k, v in value.items(): 256 | value_list.append({'building': k, 'classrooms': v}) 257 | value_list.sort(key=lambda x: x['classrooms'][0]['name']) 258 | free_classroom_dict[key] = value 259 | return free_classroom_dict 260 | 261 | 262 | def main(): 263 | parser = argparse.ArgumentParser() 264 | parser.add_argument("-o", "--output", help=" writes our JSON file to this path", required=True) 265 | parser.add_argument('-c', '--classroom', nargs='+', help=' classroom files', required=True) 266 | parser.add_argument('-g', '--graduate', nargs='+', help=' classroom files') 267 | args = parser.parse_args() 268 | graduate = [] if not args.graduate else args.graduate 269 | classrooms = get_classrooms(args.classroom, graduate) 270 | filtered = filter_classrooms(classrooms, function_allow_list=['多媒体'], name_deny_list=['教师自行安排', '网络教室', '体育', '虚拟']) 271 | result = get_free_classroom_dict(get_classroom_dict(filtered)) 272 | with open(args.output, mode='w', encoding='utf-8') as f: 273 | json.dump(result, f, indent=4, ensure_ascii=False) 274 | f.close() 275 | 276 | 277 | if __name__ == '__main__': 278 | main() 279 | -------------------------------------------------------------------------------- /src/utils/run.example.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # use root user to execute this script 4 | 5 | pkill uvicorn 6 | echo YOUR_PASSWORD_HERE | openconnect --protocol=gp --user=YOUR_USERNAME_HERE --passwd-on-stdin vpn.bupt.edu.cn& 7 | sleep 60 8 | python3 jwgl.py 9 | pkill openconnect 10 | SLEEP_LIST=result.json JWGL_LIST=jwgl.json uvicorn backend:app --host 0.0.0.0 --port 4514& --------------------------------------------------------------------------------