From a13b9c5ef1cb9096fcabd6274dbed022e93e5867 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 10 Apr 2026 12:18:09 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=89=8D=E7=AB=AF=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E5=BC=80=E5=8F=91=20-=20=E9=A6=96=E9=A1=B5/=E5=9F=8E=E5=B8=82?= =?UTF-8?q?=E5=88=97=E8=A1=A8/=E5=8C=BA=E5=9F=9F=E8=AF=A6=E6=83=85=20+=20?= =?UTF-8?q?=E7=A4=BA=E4=BE=8B=E6=95=B0=E6=8D=AE=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- city-manual/backend/db.sqlite3 | Bin 327680 -> 335872 bytes .../backend/regions/management/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 173 bytes .../regions/management/commands/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 182 bytes .../__pycache__/seed_data.cpython-312.pyc | Bin 0 -> 11557 bytes .../regions/management/commands/seed_data.py | 225 ++ city-manual/backend/seed.sh | 3 + city-manual/frontend/dev.sh | 3 + city-manual/frontend/install.sh | 3 + city-manual/frontend/package-lock.json | 2630 +++++++++++++++++ city-manual/frontend/package.json | 4 +- city-manual/frontend/src/App.jsx | 175 +- city-manual/frontend/src/api.js | 68 + city-manual/frontend/src/pages/Cities.css | 171 ++ city-manual/frontend/src/pages/Cities.jsx | 135 + city-manual/frontend/src/pages/Home.css | 228 ++ city-manual/frontend/src/pages/Home.jsx | 101 + .../frontend/src/pages/RegionDetail.css | 335 +++ .../frontend/src/pages/RegionDetail.jsx | 224 ++ 20 files changed, 4190 insertions(+), 115 deletions(-) create mode 100644 city-manual/backend/regions/management/__init__.py create mode 100644 city-manual/backend/regions/management/__pycache__/__init__.cpython-312.pyc create mode 100644 city-manual/backend/regions/management/commands/__init__.py create mode 100644 city-manual/backend/regions/management/commands/__pycache__/__init__.cpython-312.pyc create mode 100644 city-manual/backend/regions/management/commands/__pycache__/seed_data.cpython-312.pyc create mode 100644 city-manual/backend/regions/management/commands/seed_data.py create mode 100644 city-manual/backend/seed.sh create mode 100644 city-manual/frontend/dev.sh create mode 100644 city-manual/frontend/install.sh create mode 100644 city-manual/frontend/package-lock.json create mode 100644 city-manual/frontend/src/api.js create mode 100644 city-manual/frontend/src/pages/Cities.css create mode 100644 city-manual/frontend/src/pages/Cities.jsx create mode 100644 city-manual/frontend/src/pages/Home.css create mode 100644 city-manual/frontend/src/pages/Home.jsx create mode 100644 city-manual/frontend/src/pages/RegionDetail.css create mode 100644 city-manual/frontend/src/pages/RegionDetail.jsx diff --git a/city-manual/backend/db.sqlite3 b/city-manual/backend/db.sqlite3 index d5e9151ac8b3d0bc58da5add4c443fd4020f086b..7f75e4845a93fbde26aeacdcd574f365fe06f602 100644 GIT binary patch delta 9634 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 Jbb5`J{|8BD@oWG9 delta 292 zcmZoTAkxqvGC`Wvl!1XEV4{LOqv^(kh4SkBmly>2TA28E^FQTl;a|f)oxg>@m_Lr+ zi{Ff2gzr1wb-rzUGx@J=7A%P2lM-fT)@DpBEy;*4NG;0EEH2K>&vTI$Wwzy*esLL# z1gpF-vn$8+jgl-fldtQ=iwJQuYjY&$=ar=9mBc3&m1HL8q)ztI?+^w$frVF$S&_4} zIJKxa9zgMWz#j&*%!hw+SpGU7|2qT!_sxP0Z~2?Q*Khw`&&cbrndQSD z`9&KH7HtsNrohA^u$g7SAA2xgVF@EhbPFSkz;YG=<^Yh4{1Qe1m?V$^lVoYw%yQu` R|8~X&EX+U?K7dRR003|NV1xhw diff --git a/city-manual/backend/regions/management/__init__.py b/city-manual/backend/regions/management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/city-manual/backend/regions/management/__pycache__/__init__.cpython-312.pyc b/city-manual/backend/regions/management/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b2674d747fff26dec8634d31d5cabbf79285b36d GIT binary patch literal 173 zcmX@j%ge<81TL>`WP<3&AOanHW&w&!XQ*V*Wb|9fP{ah}eFmxd<)dGepI@S{mtT;Y zmzJmtkIamWj77{q764cOEsg*H literal 0 HcmV?d00001 diff --git a/city-manual/backend/regions/management/commands/__init__.py b/city-manual/backend/regions/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/city-manual/backend/regions/management/commands/__pycache__/__init__.cpython-312.pyc b/city-manual/backend/regions/management/commands/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ccae35607282583aa10c4f159ac78569a96a2fe0 GIT binary patch literal 182 zcmX@j%ge<81TL>`WP<3&AOanHW&w&!XQ*V*Wb|9fP{ah}eFmxd6{=s9pI@S{mtT;Y zmz< literal 0 HcmV?d00001 diff --git a/city-manual/backend/regions/management/commands/__pycache__/seed_data.cpython-312.pyc b/city-manual/backend/regions/management/commands/__pycache__/seed_data.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..072395658f15f08451852590400ab228973edc9d GIT binary patch literal 11557 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 SM!p{wl3Dr5|48)9G5sIkAqoxv literal 0 HcmV?d00001 diff --git a/city-manual/backend/regions/management/commands/seed_data.py b/city-manual/backend/regions/management/commands/seed_data.py new file mode 100644 index 0000000..3995ee8 --- /dev/null +++ b/city-manual/backend/regions/management/commands/seed_data.py @@ -0,0 +1,225 @@ +from django.core.management.base import BaseCommand +from django.utils import timezone +from datetime import timedelta +from regions.models import Region, ModeratorApplication +from users.models import User +from content.models import Article +from services.models import FeaturedService + + +class Command(BaseCommand): + help = '导入示例城市数据' + + def handle(self, *args, **options): + self.stdout.write('开始导入示例数据...') + + # 创建示例用户 + user, _ = User.objects.get_or_create( + username='demo', + defaults={ + 'email': 'demo@citymanual.com', + 'is_verified': True, + } + ) + user.set_password('demo123') + user.save() + + # 创建省级区域 + provinces_data = [ + {'name': '北京市', 'code': '110000', 'description': '中华人民共和国首都,全国政治中心、文化中心、国际交往中心、科技创新中心。'}, + {'name': '上海市', 'code': '310000', 'description': '中国最大的经济中心和港口城市,国际金融中心,国际贸易中心。'}, + {'name': '广东省', 'code': '440000', 'description': '中国经济最发达的省份之一,改革开放的前沿阵地。'}, + {'name': '浙江省', 'code': '330000', 'description': '中国东南沿海省份,经济发达,民营经济活跃。'}, + {'name': '四川省', 'code': '510000', 'description': '中国西南地区重要省份,天府之国,美食之都。'}, + {'name': '陕西省', 'code': '610000', 'description': '中华文明重要发祥地,十三朝古都所在地,历史文化底蕴深厚。'}, + ] + + provinces = [] + for prov_data in provinces_data: + province, created = Region.objects.get_or_create( + name=prov_data['name'], + defaults={ + 'level': 'province', + 'code': prov_data['code'], + 'description': prov_data['description'], + 'is_active': True, + } + ) + provinces.append(province) + if created: + self.stdout.write(f'✓ 创建省份:{province.name}') + + # 创建市级区域 + cities_data = [ + {'name': '广州市', 'parent': '广东省', 'code': '440100', 'description': '广东省省会,国家中心城市,国际商贸中心。'}, + {'name': '深圳市', 'parent': '广东省', 'code': '440300', 'description': '经济特区,科技创新中心,中国硅谷。'}, + {'name': '杭州市', 'parent': '浙江省', 'code': '330100', 'description': '浙江省省会,电子商务之都,风景秀丽。'}, + {'name': '宁波市', 'parent': '浙江省', 'code': '330200', 'description': '副省级市,计划单列市,重要的港口城市。'}, + {'name': '成都市', 'parent': '四川省', 'code': '510100', 'description': '四川省省会,天府之国核心,美食之都。'}, + {'name': '绵阳市', 'parent': '四川省', 'code': '510700', 'description': '四川省第二大城市,中国科技城。'}, + {'name': '西安市', 'parent': '陕西省', 'code': '610100', 'description': '陕西省省会,十三朝古都,世界历史名城。'}, + {'name': '咸阳市', 'parent': '陕西省', 'code': '610400', 'description': '中国第一个封建帝国秦朝的都城所在地。'}, + ] + + cities = [] + for city_data in cities_data: + parent = Region.objects.filter(name=city_data['parent']).first() + if parent: + city, created = Region.objects.get_or_create( + name=city_data['name'], + defaults={ + 'level': 'city', + 'parent': parent, + 'code': city_data['code'], + 'description': city_data['description'], + 'is_active': True, + } + ) + cities.append(city) + if created: + self.stdout.write(f'✓ 创建城市:{city.name}') + + # 创建示例文章 + articles_data = [ + { + 'title': '北京故宫游览完全攻略', + 'content': '故宫,旧称紫禁城,是中国明清两代的皇家宫殿,位于北京中轴线的中心。故宫以三大殿为中心,占地面积约 72 万平方米,建筑面积约 15 万平方米,有大小宫殿七十多座,房屋九千余间。是世界上现存规模最大、保存最为完整的木质结构古建筑之一。\n\n游览建议:\n1. 最佳游览时间:春秋两季\n2. 建议游览时长:3-4 小时\n3. 必游景点:太和殿、乾清宫、御花园\n4. 门票:旺季 60 元,淡季 40 元', + 'region_name': '北京市', + 'content_type': 'tourism', + }, + { + 'title': '上海外滩历史与现状', + 'content': '外滩位于上海市黄浦区的黄浦江畔,即外黄浦滩,为中国历史文化街区。1844 年(清道光廿四年)起,外滩这一带被划为英国租界,成为上海十里洋场的真实写照,也是旧上海租界区以及整个上海近代城市开始的起点。\n\n外滩全长 1.5 千米,南起延安东路,北至苏州河上的外白渡桥,东面即黄浦江,西面是历史风格建筑群。', + 'region_name': '上海市', + 'content_type': 'history', + }, + { + 'title': '广州早茶文化指南', + 'content': '广州早茶是广州饮食文化的重要组成部分,也是岭南文化的重要体现。广州人饮早茶,不仅是品尝美食,更是一种社交方式和生活方式。\n\n经典茶点:\n- 虾饺:晶莹剔透,鲜美弹牙\n- 烧卖:皮薄馅足,肉香四溢\n- 肠粉:滑嫩爽口,酱汁鲜美\n- 叉烧包:甜咸适中,松软可口\n\n推荐茶楼:陶陶居、广州酒家、莲香楼', + 'region_name': '广州市', + 'content_type': 'culture', + }, + { + 'title': '深圳科技创新发展报告', + 'content': '深圳作为中国改革开放的窗口和经济特区,40 多年来从一个小渔村发展成为国际化创新型城市。深圳拥有华为、腾讯、大疆等众多知名科技企业,被誉为"中国硅谷"。\n\n2025 年深圳 PCT 国际专利申请量连续多年居全国城市首位,战略性新兴产业增加值占 GDP 比重超过 40%。', + 'region_name': '深圳市', + 'content_type': 'city_info', + }, + { + 'title': '杭州西湖十景详解', + 'content': '西湖十景是杭州西湖最具代表性的十个景点,形成于南宋时期。每个景点都有其独特的自然风光和文化内涵。\n\n十景包括:\n1. 苏堤春晓\n2. 曲院风荷\n3. 平湖秋月\n4. 断桥残雪\n5. 花港观鱼\n6. 柳浪闻莺\n7. 三潭印月\n8. 双峰插云\n9. 雷峰夕照\n10. 南屏晚钟', + 'region_name': '杭州市', + 'content_type': 'tourism', + }, + { + 'title': '成都美食地图', + 'content': '成都,被联合国教科文组织授予"美食之都"称号,是中国乃至世界的美食天堂。川菜以其麻、辣、鲜、香的特色闻名世界。\n\n必吃美食:\n- 火锅:麻辣鲜香,回味无穷\n- 串串香:成都特色,街头美食\n- 麻婆豆腐:经典川菜,麻辣鲜香\n- 夫妻肺片:凉拌菜经典\n- 担担面:传统面食\n\n美食街区:锦里、宽窄巷子、春熙路', + 'region_name': '成都市', + 'content_type': 'life', + }, + { + 'title': '西安兵马俑参观指南', + 'content': '秦始皇兵马俑博物馆位于西安市临潼区,是中国第一个封建皇帝秦始皇的陵墓陪葬坑,被誉为"世界第八大奇迹"。\n\n参观信息:\n- 开放时间:8:30-18:00\n- 门票:120 元\n- 建议游览:2-3 小时\n- 最佳季节:春秋两季\n\n兵马俑坑共有三个,其中一号坑最大,展示了完整的军阵布局。', + 'region_name': '西安市', + 'content_type': 'tourism', + }, + ] + + for article_data in articles_data: + region = Region.objects.filter(name=article_data['region_name']).first() + if region: + article, created = Article.objects.get_or_create( + title=article_data['title'], + defaults={ + 'content': article_data['content'], + 'region': region, + 'content_type': article_data['content_type'], + 'author': user, + 'moderator_status': 'approved', + 'moderator_reviewed_at': timezone.now(), + 'ai_status': 'approved', + 'ai_reviewed_at': timezone.now(), + 'publish_status': 'published', + } + ) + if created: + self.stdout.write(f'✓ 创建文章:{article.title}') + + # 创建示例特色服务 + services_data = [ + { + 'name': '全聚德烤鸭店 (北京)', + 'description': '中华老字号,创建于 1864 年,以挂炉烤鸭闻名。全聚德烤鸭以其色泽红润、肉质肥而不腻、外脆里嫩的特点著称。', + 'region_name': '北京市', + 'category': 'food', + 'address': '北京市东城区前门大街 32 号', + 'price_range': '人均 150-300 元', + }, + { + 'name': '上海东方明珠塔', + 'description': '上海标志性建筑,高 468 米,集观光、餐饮、娱乐、购物于一体。登上观光层可俯瞰整个上海市区。', + 'region_name': '上海市', + 'category': 'tourism', + 'address': '上海市浦东新区陆家嘴世纪大道 1 号', + 'price_range': '门票 199 元起', + }, + { + 'name': '广州塔 (小蛮腰)', + 'description': '广州地标建筑,高 600 米,中国第一高塔。设有观光层、摩天轮、极速云霄等游乐项目。', + 'region_name': '广州市', + 'category': 'tourism', + 'address': '广州市海珠区阅江西路 222 号', + 'price_range': '门票 150 元起', + }, + { + 'name': '杭州楼外楼', + 'description': '百年老字号餐厅,创建于 1848 年,以杭帮菜闻名。招牌菜包括西湖醋鱼、龙井虾仁、叫花童鸡等。', + 'region_name': '杭州市', + 'category': 'food', + 'address': '杭州市西湖区孤山路 30 号', + 'price_range': '人均 200-400 元', + }, + { + 'name': '成都宽窄巷子', + 'description': '成都著名历史文化街区,由宽巷子、窄巷子、井巷子组成。集美食、购物、文化体验于一体。', + 'region_name': '成都市', + 'category': 'tourism', + 'address': '成都市青羊区长顺上街 127 号', + 'price_range': '免费开放', + }, + { + 'name': '西安大唐不夜城', + 'description': '以盛唐文化为背景的主题街区,夜景璀璨,有各种表演、美食、文创店铺,是西安夜生活的代表。', + 'region_name': '西安市', + 'category': 'entertainment', + 'address': '西安市雁塔区曲江新区', + 'price_range': '免费开放', + }, + ] + + for service_data in services_data: + region = Region.objects.filter(name=service_data['region_name']).first() + if region: + service, created = FeaturedService.objects.get_or_create( + name=service_data['name'], + defaults={ + 'description': service_data['description'], + 'region': region, + 'category': service_data['category'], + 'address': service_data.get('address', ''), + 'price_range': service_data.get('price_range', ''), + 'submitter': user, + 'moderator_status': 'approved', + 'moderator_reviewed_at': timezone.now(), + 'ai_status': 'approved', + 'ai_reviewed_at': timezone.now(), + 'publish_status': 'published', + } + ) + if created: + self.stdout.write(f'✓ 创建服务:{service.name}') + + self.stdout.write(self.style.SUCCESS('\n✅ 示例数据导入完成!')) + self.stdout.write('\n测试账号:') + self.stdout.write(' 用户名:demo') + self.stdout.write(' 密码:demo123') diff --git a/city-manual/backend/seed.sh b/city-manual/backend/seed.sh new file mode 100644 index 0000000..6b28764 --- /dev/null +++ b/city-manual/backend/seed.sh @@ -0,0 +1,3 @@ +#!/bin/bash +cd /root/.openclaw/workspace/city-manual/backend +python3 manage.py seed_data diff --git a/city-manual/frontend/dev.sh b/city-manual/frontend/dev.sh new file mode 100644 index 0000000..a3529c1 --- /dev/null +++ b/city-manual/frontend/dev.sh @@ -0,0 +1,3 @@ +#!/bin/bash +cd /root/.openclaw/workspace/city-manual/frontend +npm run dev -- --host 0.0.0.0 --port 3000 2>&1 diff --git a/city-manual/frontend/install.sh b/city-manual/frontend/install.sh new file mode 100644 index 0000000..a181ce0 --- /dev/null +++ b/city-manual/frontend/install.sh @@ -0,0 +1,3 @@ +#!/bin/bash +cd /root/.openclaw/workspace/city-manual/frontend +npm install --legacy-peer-deps 2>&1 diff --git a/city-manual/frontend/package-lock.json b/city-manual/frontend/package-lock.json new file mode 100644 index 0000000..d5a767e --- /dev/null +++ b/city-manual/frontend/package-lock.json @@ -0,0 +1,2630 @@ +{ + "name": "frontend", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "frontend", + "version": "0.0.0", + "dependencies": { + "axios": "^1.15.0", + "react": "^19.2.4", + "react-dom": "^19.2.4", + "react-router-dom": "^7.14.0" + }, + "devDependencies": { + "@eslint/js": "^9.39.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "eslint": "^9.39.4", + "eslint-plugin-react-hooks": "^7.0.1", + "eslint-plugin-react-refresh": "^0.5.2", + "globals": "^17.4.0", + "vite": "^8.0.4" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emnapi/core": { + "version": "1.9.2", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.9.2", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.2", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.5", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.14.0", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.4", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.3", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.124.0", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-rc.15", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.7", + "dev": true, + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.2.14", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "1.0.0-rc.7" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", + "babel-plugin-react-compiler": "^1.0.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@rolldown/plugin-babel": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + } + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.14.0", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.15.0.tgz", + "integrity": "sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", + "proxy-from-env": "^2.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.17", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.13", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/browserslist": { + "version": "4.28.2", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001787", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.334", + "dev": true, + "license": "ISC" + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "9.39.4", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "7.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "hermes-parser": "^0.25.1", + "zod": "^3.25.0 || ^4.0.0", + "zod-validation-error": "^3.5.0 || ^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.5.2", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": "^9 || ^10" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "dev": true, + "license": "ISC" + }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "17.4.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hermes-estree": { + "version": "0.25.1", + "dev": true, + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.25.1", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.25.1" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss/node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss/node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss/node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss/node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss/node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss/node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss/node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss/node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss/node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss/node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.5", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.37", + "dev": true, + "license": "MIT" + }, + "node_modules/optionator": { + "version": "0.9.4", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.9", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/proxy-from-env": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/react": { + "version": "19.2.5", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.5", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.5" + } + }, + "node_modules/react-router": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.14.0.tgz", + "integrity": "sha512-m/xR9N4LQLmAS0ZhkY2nkPA1N7gQ5TUVa5n8TgANuDTARbn1gt+zLPXEm7W0XDTbrQ2AJSJKhoa6yx1D8BcpxQ==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.14.0.tgz", + "integrity": "sha512-2G3ajSVSZMEtmTjIklRWlNvo8wICEpLihfD/0YMDxbWK2UyP5EGfnoIn9AIQGnF3G/FX0MRbHXdFcD+rL1ZreQ==", + "license": "MIT", + "dependencies": { + "react-router": "7.14.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/rolldown": { + "version": "1.0.0-rc.15", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.124.0", + "@rolldown/pluginutils": "1.0.0-rc.15" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-rc.15", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.15", + "@rolldown/binding-darwin-x64": "1.0.0-rc.15", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.15", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.15", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.15", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.15", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.15", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.15", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.15", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.15", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.15", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.15", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.15", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.15" + } + }, + "node_modules/rolldown/node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.15.tgz", + "integrity": "sha512-YYe6aWruPZDtHNpwu7+qAHEMbQ/yRl6atqb/AhznLTnD3UY99Q1jE7ihLSahNWkF4EqRPVC4SiR4O0UkLK02tA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/rolldown/node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.15.tgz", + "integrity": "sha512-oArR/ig8wNTPYsXL+Mzhs0oxhxfuHRfG7Ikw7jXsw8mYOtk71W0OkF2VEVh699pdmzjPQsTjlD1JIOoHkLP1Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/rolldown/node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.15.tgz", + "integrity": "sha512-YzeVqOqjPYvUbJSWJ4EDL8ahbmsIXQpgL3JVipmN+MX0XnXMeWomLN3Fb+nwCmP/jfyqte5I3XRSm7OfQrbyxw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/rolldown/node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.15.tgz", + "integrity": "sha512-9Erhx956jeQ0nNTyif1+QWAXDRD38ZNjr//bSHrt6wDwB+QkAfl2q6Mn1k6OBPerznjRmbM10lgRb1Pli4xZPw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/rolldown/node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.15.tgz", + "integrity": "sha512-cVwk0w8QbZJGTnP/AHQBs5yNwmpgGYStL88t4UIaqcvYJWBfS0s3oqVLZPwsPU6M0zlW4GqjP0Zq5MnAGwFeGA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/rolldown/node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.15.tgz", + "integrity": "sha512-eBZ/u8iAK9SoHGanqe/jrPnY0JvBN6iXbVOsbO38mbz+ZJsaobExAm1Iu+rxa4S1l2FjG0qEZn4Rc6X8n+9M+w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/rolldown/node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.15.tgz", + "integrity": "sha512-ZvRYMGrAklV9PEkgt4LQM6MjQX2P58HPAuecwYObY2DhS2t35R0I810bKi0wmaYORt6m/2Sm+Z+nFgb0WhXNcQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/rolldown/node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.15.tgz", + "integrity": "sha512-VDpgGBzgfg5hLg+uBpCLoFG5kVvEyafmfxGUV0UHLcL5irxAK7PKNeC2MwClgk6ZAiNhmo9FLhRYgvMmedLtnQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/rolldown/node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.15.tgz", + "integrity": "sha512-y1uXY3qQWCzcPgRJATPSOUP4tCemh4uBdY7e3EZbVwCJTY3gLJWnQABgeUetvED+bt1FQ01OeZwvhLS2bpNrAQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/rolldown/node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.15.tgz", + "integrity": "sha512-witB2O0/hU4CgfOOKUoeFgQ4GktPi1eEbAhaLAIpgD6+ZnhcPkUtPsoKKHRzmOoWPZue46IThdSgdo4XneOLYw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/rolldown/node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.15.tgz", + "integrity": "sha512-UCL68NJ0Ud5zRipXZE9dF5PmirzJE4E4BCIOOssEnM7wLDsxjc6Qb0sGDxTNRTP53I6MZpygyCpY8Aa8sPfKPg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/rolldown/node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.15.tgz", + "integrity": "sha512-ApLruZq/ig+nhaE7OJm4lDjayUnOHVUa77zGeqnqZ9pn0ovdVbbNPerVibLXDmWeUZXjIYIT8V3xkT58Rm9u5Q==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.9.2", + "@emnapi/runtime": "1.9.2", + "@napi-rs/wasm-runtime": "^1.1.3" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/rolldown/node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.15.tgz", + "integrity": "sha512-KmoUoU7HnN+Si5YWJigfTws1jz1bKBYDQKdbLspz0UaqjjFkddHsqorgiW1mxcAj88lYUE6NC/zJNwT+SloqtA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/rolldown/node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.15.tgz", + "integrity": "sha512-3P2A8L+x75qavWLe/Dll3EYBJLQmtkJN8rfh+U/eR3MqMgL/h98PhYI+JFfXuDPgPeCB7iZAKiqii5vqOvnA0g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/rolldown/node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.15", + "dev": true, + "license": "MIT" + }, + "node_modules/scheduler": { + "version": "0.27.0", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.16", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "dev": true, + "license": "0BSD", + "optional": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vite": { + "version": "8.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.8", + "rolldown": "1.0.0-rc.15", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.3.6", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-validation-error": { + "version": "4.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } + } + } +} diff --git a/city-manual/frontend/package.json b/city-manual/frontend/package.json index 2576dba..2cb299e 100644 --- a/city-manual/frontend/package.json +++ b/city-manual/frontend/package.json @@ -10,8 +10,10 @@ "preview": "vite preview" }, "dependencies": { + "axios": "^1.15.0", "react": "^19.2.4", - "react-dom": "^19.2.4" + "react-dom": "^19.2.4", + "react-router-dom": "^7.14.0" }, "devDependencies": { "@eslint/js": "^9.39.4", diff --git a/city-manual/frontend/src/App.jsx b/city-manual/frontend/src/App.jsx index b2bf2e8..88e7b71 100644 --- a/city-manual/frontend/src/App.jsx +++ b/city-manual/frontend/src/App.jsx @@ -1,121 +1,68 @@ -import { useState } from 'react' -import reactLogo from './assets/react.svg' -import viteLogo from './assets/vite.svg' -import heroImg from './assets/hero.png' -import './App.css' +import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom'; +import Home from './pages/Home'; +import Cities from './pages/Cities'; +import RegionDetail from './pages/RegionDetail'; +import './App.css'; function App() { - const [count, setCount] = useState(0) - return ( - <> -
-
- - React logo - Vite logo -
-
-

Get started

-

- Edit src/App.jsx and save to test HMR -

-
- -
+ +
+ {/* Navigation */} + -
+ {/* Main Content */} +
+ + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + +
-
-
- -

Documentation

-

Your questions, answered

- -
-
- -

Connect with us

-

Join the Vite community

- -
-
- -
-
- - ) + {/* Footer */} +
+
+

© 2026 城市手册 - 记录每座城市的独特魅力

+
+
+
+
+ ); } -export default App +// 占位组件 - 后续完善 +function ArticleDetail() { + return

文章详情页

开发中...

; +} + +function ServiceDetail() { + return

服务详情页

开发中...

; +} + +function Login() { + return

登录

开发中...

; +} + +function Register() { + return

注册

开发中...

; +} + +export default App; diff --git a/city-manual/frontend/src/api.js b/city-manual/frontend/src/api.js new file mode 100644 index 0000000..b811d00 --- /dev/null +++ b/city-manual/frontend/src/api.js @@ -0,0 +1,68 @@ +import axios from 'axios'; + +const API_BASE = 'http://localhost:8000/api'; + +const api = axios.create({ + baseURL: API_BASE, + headers: { + 'Content-Type': 'application/json', + }, +}); + +// 请求拦截器 - 添加 token +api.interceptors.request.use((config) => { + const token = localStorage.getItem('token'); + if (token) { + config.headers.Authorization = `Bearer ${token}`; + } + return config; +}); + +// 响应拦截器 - 处理错误 +api.interceptors.response.use( + (response) => response, + (error) => { + if (error.response?.status === 401) { + localStorage.removeItem('token'); + window.location.href = '/login'; + } + return Promise.reject(error); + } +); + +export const regionsApi = { + getList: () => api.get('/regions/'), + getDetail: (id) => api.get(`/regions/${id}/`), + getProvinces: () => api.get('/regions/provinces/'), + getChildren: (id) => api.get(`/regions/${id}/children/`), +}; + +export const articlesApi = { + getList: (params) => api.get('/articles/', { params }), + getDetail: (id) => api.get(`/articles/${id}/`), + create: (data) => api.post('/articles/', data), +}; + +export const servicesApi = { + getList: (params) => api.get('/services/', { params }), + getDetail: (id) => api.get(`/services/${id}/`), + create: (data) => api.post('/services/', data), +}; + +export const usersApi = { + register: (data) => api.post('/register/', data), + login: (data) => api.post('/token/', data), + getMe: () => api.get('/users/me/'), +}; + +export const commentsApi = { + getList: () => api.get('/comments/'), + create: (data) => api.post('/comments/', data), +}; + +export const ratingsApi = { + getList: () => api.get('/ratings/'), + create: (data) => api.post('/ratings/', data), +}; + +export default api; diff --git a/city-manual/frontend/src/pages/Cities.css b/city-manual/frontend/src/pages/Cities.css new file mode 100644 index 0000000..906139d --- /dev/null +++ b/city-manual/frontend/src/pages/Cities.css @@ -0,0 +1,171 @@ +.cities-page { + min-height: 100vh; + padding: 40px 20px; + background: #f8f9fa; +} + +.container { + max-width: 1200px; + margin: 0 auto; +} + +/* Breadcrumb */ +.breadcrumb { + margin-bottom: 30px; + font-size: 0.95rem; +} + +.breadcrumb a { + color: #667eea; + text-decoration: none; +} + +.breadcrumb a:hover { + text-decoration: underline; +} + +.breadcrumb .separator { + margin: 0 10px; + color: #999; +} + +/* Region Header */ +.region-header { + background: white; + padding: 40px; + border-radius: 12px; + margin-bottom: 30px; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); +} + +.region-header h1 { + font-size: 2.5rem; + color: #333; + margin-bottom: 15px; +} + +.region-description { + color: #666; + font-size: 1.1rem; + line-height: 1.6; + margin-bottom: 20px; +} + +.region-stats { + display: flex; + gap: 30px; +} + +.stat { + color: #667eea; + font-weight: bold; + font-size: 1rem; +} + +/* Region Grid */ +.region-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); + gap: 20px; +} + +.region-card { + background: white; + padding: 30px 25px; + border-radius: 12px; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); + text-decoration: none; + color: #333; + text-align: center; + transition: transform 0.3s, box-shadow 0.3s; +} + +.region-card:hover { + transform: translateY(-5px); + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15); +} + +.region-icon { + font-size: 3rem; + margin-bottom: 15px; +} + +.region-card h3 { + font-size: 1.3rem; + margin-bottom: 10px; + color: #333; +} + +.region-level { + color: #667eea; + font-size: 0.9rem; + margin-bottom: 8px; +} + +.region-children { + color: #999; + font-size: 0.85rem; +} + +/* Empty State */ +.empty-state { + background: white; + padding: 60px 40px; + border-radius: 12px; + text-align: center; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); +} + +.empty-state p { + color: #666; + font-size: 1.1rem; + margin-bottom: 20px; +} + +.btn-link { + color: #667eea; + text-decoration: none; + font-weight: bold; +} + +.btn-link:hover { + text-decoration: underline; +} + +/* Loading */ +.loading { + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + font-size: 1.5rem; + color: #666; +} + +/* Responsive */ +@media (max-width: 768px) { + .cities-page { + padding: 20px 15px; + } + + .region-header { + padding: 25px 20px; + } + + .region-header h1 { + font-size: 1.8rem; + } + + .region-grid { + grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); + gap: 15px; + } + + .region-card { + padding: 20px 15px; + } + + .region-icon { + font-size: 2.5rem; + } +} diff --git a/city-manual/frontend/src/pages/Cities.jsx b/city-manual/frontend/src/pages/Cities.jsx new file mode 100644 index 0000000..4d50285 --- /dev/null +++ b/city-manual/frontend/src/pages/Cities.jsx @@ -0,0 +1,135 @@ +import { useState, useEffect } from 'react'; +import { Link, useParams } from 'react-router-dom'; +import { regionsApi } from '../api'; +import './Cities.css'; + +function Cities() { + const { provinceId } = useParams(); + const [regions, setRegions] = useState([]); + const [currentRegion, setCurrentRegion] = useState(null); + const [loading, setLoading] = useState(true); + const [breadcrumb, setBreadcrumb] = useState([]); + + useEffect(() => { + loadRegions(); + }, [provinceId]); + + async function loadRegions() { + setLoading(true); + try { + if (provinceId) { + // 加载省份详情和子区域 + const [detailRes, childrenRes] = await Promise.all([ + regionsApi.getDetail(provinceId), + regionsApi.getChildren(provinceId), + ]); + setCurrentRegion(detailRes.data); + setRegions(childrenRes.data); + setBreadcrumb([ + { id: null, name: '全部省份' }, + { id: provinceId, name: detailRes.data.name }, + ]); + } else { + // 加载所有省份 + const res = await regionsApi.getProvinces(); + setRegions(res.data); + setCurrentRegion(null); + setBreadcrumb([{ id: null, name: '全部省份' }]); + } + } catch (error) { + console.error('加载区域失败:', error); + } finally { + setLoading(false); + } + } + + if (loading) { + return
加载中...
; + } + + return ( +
+
+ {/* 面包屑导航 */} + + + {/* 当前区域信息 */} + {currentRegion && ( +
+

{currentRegion.name}

+ {currentRegion.description && ( +

{currentRegion.description}

+ )} +
+ + 📝 {currentRegion.articles_count || 0} 篇文章 + + + 🏪 {currentRegion.services_count || 0} 个服务 + +
+
+ )} + + {/* 子区域列表 */} + {regions.length > 0 ? ( +
+ {regions.map((region) => ( + +
+ {region.level === 'province' && '🏔️'} + {region.level === 'city' && '🏙️'} + {region.level === 'county' && '🏘️'} + {region.level === 'town' && '🏡'} + {region.level === 'village' && '🏠'} +
+

{region.name}

+

{getLevelName(region.level)}

+ {region.children_count > 0 && ( +

{region.children_count} 个下级区域

+ )} + + ))} +
+ ) : ( +
+

暂无下级区域

+ + 查看该区域的文章 → + +
+ )} +
+
+ ); +} + +function getLevelName(level) { + const map = { + province: '省级', + city: '市级', + county: '县级', + town: '镇级', + village: '村级', + }; + return map[level] || level; +} + +export default Cities; diff --git a/city-manual/frontend/src/pages/Home.css b/city-manual/frontend/src/pages/Home.css new file mode 100644 index 0000000..4b491c0 --- /dev/null +++ b/city-manual/frontend/src/pages/Home.css @@ -0,0 +1,228 @@ +.home { + min-height: 100vh; +} + +.loading { + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + font-size: 1.5rem; + color: #666; +} + +/* Hero Section */ +.hero { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + padding: 120px 20px; + text-align: center; +} + +.hero-content h1 { + font-size: 3.5rem; + margin-bottom: 20px; + font-weight: bold; +} + +.hero-content p { + font-size: 1.3rem; + margin-bottom: 30px; + opacity: 0.9; +} + +.btn-primary { + display: inline-block; + background: white; + color: #667eea; + padding: 15px 40px; + border-radius: 30px; + text-decoration: none; + font-weight: bold; + font-size: 1.1rem; + transition: transform 0.3s, box-shadow 0.3s; +} + +.btn-primary:hover { + transform: translateY(-3px); + box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2); +} + +/* Section */ +.section { + padding: 80px 20px; +} + +.section-alt { + background: #f8f9fa; +} + +.container { + max-width: 1200px; + margin: 0 auto; +} + +.section-title { + text-align: center; + font-size: 2rem; + margin-bottom: 50px; + color: #333; + position: relative; +} + +.section-title::after { + content: ''; + display: block; + width: 60px; + height: 4px; + background: #667eea; + margin: 15px auto 0; + border-radius: 2px; +} + +/* Province Grid */ +.province-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); + gap: 20px; +} + +.province-card { + background: white; + padding: 30px; + border-radius: 12px; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); + text-decoration: none; + color: #333; + transition: transform 0.3s, box-shadow 0.3s; + border: 2px solid transparent; +} + +.province-card:hover { + transform: translateY(-5px); + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15); + border-color: #667eea; +} + +.province-card h3 { + font-size: 1.5rem; + margin-bottom: 10px; + color: #667eea; +} + +.province-card p { + color: #666; + font-size: 0.95rem; +} + +/* Article Grid */ +.article-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + gap: 25px; +} + +.article-card { + background: white; + padding: 25px; + border-radius: 12px; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); + text-decoration: none; + color: #333; + transition: transform 0.3s, box-shadow 0.3s; +} + +.article-card:hover { + transform: translateY(-5px); + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15); +} + +.article-card h3 { + font-size: 1.3rem; + margin-bottom: 10px; + color: #333; +} + +.article-meta { + color: #667eea; + font-size: 0.9rem; + margin-bottom: 15px; +} + +.article-excerpt { + color: #666; + line-height: 1.6; + font-size: 0.95rem; +} + +/* Service Grid */ +.service-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); + gap: 20px; +} + +.service-card { + background: white; + padding: 25px; + border-radius: 12px; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); + text-decoration: none; + color: #333; + transition: transform 0.3s, box-shadow 0.3s; + position: relative; + overflow: hidden; +} + +.service-card:hover { + transform: translateY(-5px); + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15); +} + +.service-category { + position: absolute; + top: 15px; + right: 15px; + background: #667eea; + color: white; + padding: 5px 12px; + border-radius: 20px; + font-size: 0.8rem; +} + +.service-card h3 { + font-size: 1.2rem; + margin-bottom: 10px; + color: #333; +} + +.service-location { + color: #666; + font-size: 0.9rem; + margin-bottom: 10px; +} + +.service-rating { + color: #f5a623; + font-weight: bold; + font-size: 0.95rem; +} + +/* Responsive */ +@media (max-width: 768px) { + .hero-content h1 { + font-size: 2.5rem; + } + + .hero-content p { + font-size: 1.1rem; + } + + .section { + padding: 50px 15px; + } + + .section-title { + font-size: 1.6rem; + } +} diff --git a/city-manual/frontend/src/pages/Home.jsx b/city-manual/frontend/src/pages/Home.jsx new file mode 100644 index 0000000..31bfe5e --- /dev/null +++ b/city-manual/frontend/src/pages/Home.jsx @@ -0,0 +1,101 @@ +import { useState, useEffect } from 'react'; +import { Link } from 'react-router-dom'; +import { regionsApi, articlesApi, servicesApi } from '../api'; +import './Home.css'; + +function Home() { + const [provinces, setProvinces] = useState([]); + const [featuredArticles, setFeaturedArticles] = useState([]); + const [featuredServices, setFeaturedServices] = useState([]); + const [loading, setLoading] = useState(true); + + useEffect(() => { + loadData(); + }, []); + + async function loadData() { + try { + const [provincesRes, articlesRes, servicesRes] = await Promise.all([ + regionsApi.getProvinces(), + articlesApi.getList({ limit: 6 }), + servicesApi.getList({ limit: 6 }), + ]); + setProvinces(provincesRes.data.slice(0, 6)); + setFeaturedArticles(articlesRes.data.results || articlesRes.data.slice(0, 6)); + setFeaturedServices(servicesRes.data.results || servicesRes.data.slice(0, 6)); + } catch (error) { + console.error('加载数据失败:', error); + } finally { + setLoading(false); + } + } + + if (loading) { + return
加载中...
; + } + + return ( +
+ {/* Hero Section */} +
+
+

城市手册

+

探索每座城市的独特魅力

+ 开始探索 +
+
+ + {/* 省份导航 */} +
+
+

热门省份

+
+ {provinces.map((province) => ( + +

{province.name}

+

{province.level === 'province' ? '省级行政区' : province.level}

+ + ))} +
+
+
+ + {/* 精选文章 */} +
+
+

精选内容

+
+ {featuredArticles.map((article) => ( + +

{article.title}

+

{article.region?.name} · {article.content_type}

+

{article.content?.substring(0, 100)}...

+ + ))} +
+
+
+ + {/* 特色服务 */} +
+
+

特色服务

+
+ {featuredServices.map((service) => ( + +
{service.category}
+

{service.name}

+

{service.region?.name}

+ {service.rating_average > 0 && ( +
⭐ {service.rating_average.toFixed(1)}
+ )} + + ))} +
+
+
+
+ ); +} + +export default Home; diff --git a/city-manual/frontend/src/pages/RegionDetail.css b/city-manual/frontend/src/pages/RegionDetail.css new file mode 100644 index 0000000..07d9e0c --- /dev/null +++ b/city-manual/frontend/src/pages/RegionDetail.css @@ -0,0 +1,335 @@ +.region-detail { + min-height: 100vh; + background: #f8f9fa; +} + +/* Header */ +.region-header { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + padding: 60px 20px 40px; +} + +.region-header .container { + max-width: 1200px; + margin: 0 auto; +} + +.breadcrumb { + margin-bottom: 20px; + opacity: 0.9; +} + +.breadcrumb a { + color: white; + text-decoration: none; +} + +.breadcrumb a:hover { + text-decoration: underline; +} + +.breadcrumb .separator { + margin: 0 10px; +} + +.region-header h1 { + font-size: 3rem; + margin-bottom: 15px; + font-weight: bold; +} + +.description { + font-size: 1.2rem; + line-height: 1.6; + margin-bottom: 20px; + opacity: 0.95; +} + +.tags { + display: flex; + gap: 10px; + flex-wrap: wrap; +} + +.tag { + background: rgba(255, 255, 255, 0.2); + padding: 6px 15px; + border-radius: 20px; + font-size: 0.9rem; +} + +/* Tabs */ +.tabs-container { + background: white; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); + position: sticky; + top: 0; + z-index: 100; +} + +.tabs { + display: flex; + gap: 5px; + overflow-x: auto; +} + +.tab { + padding: 18px 30px; + border: none; + background: none; + font-size: 1rem; + color: #666; + cursor: pointer; + position: relative; + transition: color 0.3s; + white-space: nowrap; +} + +.tab:hover { + color: #667eea; +} + +.tab.active { + color: #667eea; + font-weight: bold; +} + +.tab.active::after { + content: ''; + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 3px; + background: #667eea; +} + +/* Content */ +.content { + padding: 40px 20px; +} + +/* Overview */ +.stats-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 20px; + margin-bottom: 40px; +} + +.stat-card { + background: white; + padding: 30px; + border-radius: 12px; + text-align: center; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); +} + +.stat-number { + font-size: 3rem; + font-weight: bold; + color: #667eea; + margin-bottom: 10px; +} + +.stat-label { + color: #666; + font-size: 1rem; +} + +.children-section { + background: white; + padding: 30px; + border-radius: 12px; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); +} + +.children-section h2 { + margin-bottom: 25px; + color: #333; +} + +.region-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + gap: 20px; +} + +.region-card { + background: #f8f9fa; + padding: 25px; + border-radius: 12px; + text-decoration: none; + color: #333; + text-align: center; + transition: transform 0.3s, box-shadow 0.3s; +} + +.region-card:hover { + transform: translateY(-3px); + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.15); + background: white; +} + +.region-card h3 { + font-size: 1.2rem; + margin-bottom: 8px; + color: #667eea; +} + +.region-card p { + color: #666; + font-size: 0.9rem; +} + +/* Articles & Services List */ +.articles-list, +.services-list { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + gap: 20px; +} + +.article-card { + background: white; + padding: 25px; + border-radius: 12px; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); + text-decoration: none; + color: #333; + transition: transform 0.3s, box-shadow 0.3s; +} + +.article-card:hover { + transform: translateY(-3px); + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.15); +} + +.article-card h3 { + font-size: 1.2rem; + margin-bottom: 12px; + color: #333; +} + +.meta { + display: flex; + justify-content: space-between; + font-size: 0.85rem; +} + +.type { + color: #667eea; + background: #f0f2ff; + padding: 4px 10px; + border-radius: 4px; +} + +.date { + color: #999; +} + +.service-card { + background: white; + padding: 25px; + border-radius: 12px; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); + text-decoration: none; + color: #333; + transition: transform 0.3s, box-shadow 0.3s; +} + +.service-card:hover { + transform: translateY(-3px); + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.15); +} + +.service-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 12px; +} + +.service-header h3 { + font-size: 1.2rem; + color: #333; +} + +.category { + background: #667eea; + color: white; + padding: 4px 12px; + border-radius: 20px; + font-size: 0.85rem; +} + +.service-description { + color: #666; + line-height: 1.6; + margin-bottom: 15px; +} + +.rating { + color: #f5a623; + font-weight: bold; + font-size: 0.95rem; +} + +/* Empty State */ +.empty { + background: white; + padding: 60px 40px; + border-radius: 12px; + text-align: center; + color: #666; + font-size: 1.1rem; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); +} + +/* Loading */ +.loading { + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + font-size: 1.5rem; + color: #666; +} + +/* Responsive */ +@media (max-width: 768px) { + .region-header { + padding: 40px 15px 30px; + } + + .region-header h1 { + font-size: 2rem; + } + + .description { + font-size: 1rem; + } + + .tabs { + padding: 0 15px; + } + + .tab { + padding: 15px 20px; + font-size: 0.95rem; + } + + .content { + padding: 25px 15px; + } + + .stats-grid { + grid-template-columns: 1fr; + } + + .articles-list, + .services-list { + grid-template-columns: 1fr; + } +} diff --git a/city-manual/frontend/src/pages/RegionDetail.jsx b/city-manual/frontend/src/pages/RegionDetail.jsx new file mode 100644 index 0000000..a574f11 --- /dev/null +++ b/city-manual/frontend/src/pages/RegionDetail.jsx @@ -0,0 +1,224 @@ +import { useState, useEffect } from 'react'; +import { useParams, Link } from 'react-router-dom'; +import { regionsApi, articlesApi, servicesApi } from '../api'; +import './RegionDetail.css'; + +function RegionDetail() { + const { id } = useParams(); + const [region, setRegion] = useState(null); + const [articles, setArticles] = useState([]); + const [services, setServices] = useState([]); + const [children, setChildren] = useState([]); + const [loading, setLoading] = useState(true); + const [activeTab, setActiveTab] = useState('overview'); + + useEffect(() => { + loadData(); + }, [id]); + + async function loadData() { + setLoading(true); + try { + const [regionRes, articlesRes, servicesRes, childrenRes] = await Promise.all([ + regionsApi.getDetail(id), + articlesApi.getList({ region: id, limit: 10 }), + servicesApi.getList({ region: id, limit: 10 }), + regionsApi.getChildren(id), + ]); + setRegion(regionRes.data); + setArticles(articlesRes.data.results || articlesRes.data); + setServices(servicesRes.data.results || servicesRes.data); + setChildren(childrenRes.data); + } catch (error) { + console.error('加载数据失败:', error); + } finally { + setLoading(false); + } + } + + if (loading || !region) { + return
加载中...
; + } + + return ( +
+ {/* Header */} +
+
+ +

{region.name}

+ {region.description &&

{region.description}

} +
+ {getLevelName(region.level)} + {region.code && 代码:{region.code}} +
+
+
+ + {/* Tabs */} +
+
+
+ + + + +
+
+
+ + {/* Content */} +
+ {activeTab === 'overview' && ( +
+
+
+
{region.articles_count || 0}
+
文章
+
+
+
{region.services_count || 0}
+
服务
+
+
+
{children.length}
+
下级区域
+
+
+ + {children.length > 0 && ( +
+

下级区域

+
+ {children.slice(0, 6).map((child) => ( + +

{child.name}

+

{getLevelName(child.level)}

+ + ))} +
+
+ )} +
+ )} + + {activeTab === 'articles' && ( +
+ {articles.length > 0 ? ( + articles.map((article) => ( + +

{article.title}

+
+ {getContentTypeName(article.content_type)} + {new Date(article.created_at).toLocaleDateString('zh-CN')} +
+ + )) + ) : ( +
暂无文章
+ )} +
+ )} + + {activeTab === 'services' && ( +
+ {services.length > 0 ? ( + services.map((service) => ( + +
+

{service.name}

+ {getCategoryName(service.category)} +
+

{service.description?.substring(0, 100)}...

+ {service.rating_average > 0 && ( +
⭐ {service.rating_average.toFixed(1)} ({service.rating_count}条评价)
+ )} + + )) + ) : ( +
暂无服务
+ )} +
+ )} + + {activeTab === 'subregions' && ( +
+ {children.length > 0 ? ( +
+ {children.map((child) => ( + +

{child.name}

+

{getLevelName(child.level)}

+ + ))} +
+ ) : ( +
暂无下级区域
+ )} +
+ )} +
+
+ ); +} + +function getLevelName(level) { + const map = { + province: '省级', + city: '市级', + county: '县级', + town: '镇级', + village: '村级', + }; + return map[level] || level; +} + +function getContentTypeName(type) { + const map = { + city_info: '城市信息', + history: '历史', + culture: '文化', + practical: '实用信息', + life: '生活指南', + }; + return map[type] || type; +} + +function getCategoryName(category) { + const map = { + clothing: '衣', + food: '食', + housing: '住', + transportation: '行', + entertainment: '娱乐', + tourism: '旅游', + culture: '文化', + }; + return map[category] || category; +} + +export default RegionDetail;