commit f5a9e4403a8c18d9c2e86f255a1758fca3cedb8f Author: duanshuwen Date: Tue Aug 11 19:19:11 2026 +0800 chore: import WonderQ project diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..69c8cc1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +node_modules/ +dist/ +apps/*/dist/ +.env +.env.local +**/.venv/ +**/.pytest_cache/ +**/__pycache__/ +*.pyc +*.sqlite +*.db +*.pem +*.key +.DS_Store +*.log +coverage/ +.prisma/ +artifacts/ +task_plan.md +progress.md +findings.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..1dfc082 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,376 @@ +# AGENTS.md + +本文档用于约束 AI 代理参与 WonderQ 项目开发时的行为、边界和验证方式。适用于 Codex、ChatGPT、Cursor、Claude Code 等 AI 工具。 + +项目层规则优先于通用规则;进入某个子项目工作时,优先遵守该子项目技术栈、接口契约和锁定边界。 + +## 1. 全局协作规则 + +- 默认全程使用中文回答;用户明确要求其他语言时才切换。 +- 回答简洁直接,不做无效铺垫,不输出与任务无关的说明。 +- 需求不清晰、影响范围不明或涉及高风险文件时,先提问确认,不自行猜测执行。 +- 默认只读优先。创建、修改、删除文件必须先获得用户明确授权。 +- 严格按当前需求工作,不额外加功能、不扩大改动范围。 +- 修改前先阅读目标文件、相邻实现、相关类型和契约文档;修改后检查变更内容,并按影响范围运行验证。 +- 保留工作区里的用户改动,不使用 `git reset`、`git checkout --`、批量删除或覆盖无关文件。 +- 不读取、展示、复述或提交 `.env`、`.env.local`、生产环境变量、Token、密码、密钥、真实客服链接、企业 ID、客户手机号等敏感信息。 +- 文档、示例和测试只能使用占位值,不写入真实账号、密钥、联系方式或生产配置。 +- 用户提到产品设计时,优先考虑 `product design`。 +- 用户提出“调整视觉 UI”“视觉不好看”“美化界面”“优化视觉”“界面更好看”等需求时,优先考虑 `ui-ux-pro-max`,并结合项目现有设计系统落地。 + +## 2. 项目定位 + +WonderQ 是三端分离的旅行产品项目集合,当前由三个独立子项目组成: + +- `WonderQ-MiniAPP`:万趣旅行移动端前台,面向 H5 与微信小程序,技术栈为 uni-app、Vue 3、TypeScript、TailwindCSS。 +- `WonderQ-Admin-UI`:后台管理前端,用于维护首页结构、目的地、线路商品、活动入口、页面模块和客户需求线索,技术栈为 Vite、React、TypeScript、Tailwind CSS 4、shadcn/ui 风格组件。 +- `WonderQ-Admin`:后端 API 服务,为 MiniAPP 提供 Public API,为后台管理端提供 Admin API,技术栈为 Python、FastAPI、SQLAlchemy 2、Alembic、PostgreSQL、JWT、Pydantic。 + +核心开发原则是页面驱动开发:业务围绕 MiniAPP/H5 前台页面和运营配置场景展开;后台负责配置页面数据;后端负责业务逻辑、鉴权、数据持久化和接口;MiniAPP 负责展示与交互。 + +## 3. 根目录结构 + +```text +WonderQ-Project/ +├─ AGENTS.md +├─ README.md +├─ docs/ +│ ├─ README.md +│ ├─ integration-workflow.md +│ ├─ development-status.md +│ ├─ decisions.md +│ ├─ backend-api-service.md +│ ├─ backend-plan.md +│ ├─ admin-api-requirements.md +│ ├─ module-config-api.md +│ └─ public-api.md +├─ WonderQ-MiniAPP/ +├─ WonderQ-Admin-UI/ +└─ WonderQ-Admin/ +``` + +## 4. 文档入口与权威来源 + +- `docs/README.md` 是当前文档索引。 +- `docs/integration-workflow.md` 定义三端本地启动、联调顺序、接口变更流程和验证命令。 +- `docs/development-status.md` 记录三端能力对接状态,不替代实际测试结果。 +- `docs/decisions.md` 记录当前有效技术和文档决策。 +- `docs/public-api.md` 是 MiniAPP 对接后端的唯一 Public API 契约。 +- `docs/admin-api-requirements.md` 是 Admin UI 对接后端的主契约。 +- `docs/module-config-api.md` 是页面模块配置 CRUD 的唯一细节契约。 +- `docs/backend-api-service.md`、`docs/backend-plan.md` 约束后端运行、联调、部署和规划边界。 + +接口、字段、状态码或模块规则发生变化时,先更新对应契约文档,再改后端和前端实现。 + +## 5. 页面驱动开发流程 + +本项目采用页面驱动开发(Page Driven Development):先从 MiniAPP/H5 前台页面和运营配置场景定义需求,再推进数据模型、后端 API、后台管理和前台实现。 + +新增或重构面向用户的页面、模块或运营能力时,按以下顺序推进: + +1. 明确前台页面目标:用户角色、页面流程、展示模块、交互方式、空态、错误态和边界情况。 +2. 明确数据归属:哪些字段来自 Public API,哪些字段由 Admin API 维护,哪些仅为本地兜底内容。 +3. 更新契约文档:Public API 改 `public-api.md`,Admin API 改 `admin-api-requirements.md`,页面模块 CRUD 改 `module-config-api.md`。 +4. 设计后端数据与接口:数据库模型、迁移、Pydantic schema、鉴权、审计、参数校验和错误响应。 +5. 实现后端 API:保持现有路径和响应结构兼容,不随意破坏 MiniAPP 与 Admin UI 调用。 +6. 实现后台管理:围绕运营配置页面组织菜单和表单,不按数据库表名机械拆菜单。 +7. 实现 MiniAPP 展示:调用 Public API,处理 loading、empty、error、retry、分页/刷新和本地兜底。 +8. 运行三端验证:按变更范围执行后端测试、前端构建、MiniAPP 构建和必要的浏览器/小程序验证。 + +小型修复、纯文档整理、单端 UI 调整不强制输出完整八步,但不能跳过与当前任务相关的契约、安全和验证检查。 + +## 6. 三端模块分工 + +### WonderQ-MiniAPP + +```text +WonderQ-MiniAPP/ +├─ index.html +├─ package.json +├─ tsconfig.json +├─ tailwind.config.ts +├─ vitest.config.ts +├─ vite.config.ts +├─ src/ +│ ├─ main.ts +│ ├─ App.vue +│ ├─ app.css +│ ├─ manifest.json +│ ├─ pages.json +│ ├─ content.ts +│ ├─ generated-products.json +│ ├─ components/ +│ ├─ lib/ +│ └─ pages/ +├─ tests/ +├─ public/assets/ +└─ scripts/ +``` + +- `src/pages/`:首页、目的地、搜索、活动、需求、权益、预订、详情和我的页面。 +- `src/components/`:复用 Vue SFC 组件,如顶部栏、底部导航、产品卡、客服弹层、空状态和留资表单。 +- `src/lib/api.ts`:Public API 客户端与类型定义,访问 `/api/public/site-config`、`/api/public/products`、`/api/public/leads`。 +- `src/lib/data.ts`、`src/lib/store.ts`、`src/lib/navigation.ts`、`src/lib/support.ts`:业务数据归一化、共享状态、页面跳转和客服联系封装。 +- `src/content.ts`、`src/generated-products.json`:前台静态兜底内容与产品数据。 +- `public/assets/`:前台图片资源。 + +### WonderQ-Admin-UI + +```text +WonderQ-Admin-UI/ +├─ README.md +├─ components.json +├─ public/assets/ +├─ src/ +│ ├─ App.tsx +│ ├─ api.ts +│ ├─ components/ui/ +│ ├─ lib/ +│ ├─ pages/ +│ ├─ main.tsx +│ ├─ styles.css +│ └─ vite-env.d.ts +├─ index.html +├─ package.json +├─ tsconfig.json +├─ vite.config.ts +└─ yarn.lock +``` + +- `src/App.tsx`:后台应用壳、登录态、侧边导航和全局布局。 +- `src/api.ts`:Admin API 类型、Token 管理、鉴权头和请求封装。 +- `src/pages/structure/StructurePage.tsx`:首页、目的地页、需求页等页面模块配置主界面。 +- `src/pages/products/ProductsPage.tsx`:线路商品维护。 +- `src/pages/leads/LeadsPage.tsx`:需求线索查询、筛选和状态流转。 +- `src/components/ui/`:Button、Card、Input、Textarea、Badge、Alert、Switch、NativeSelect、Separator 等基础组件。 +- `src/styles.css`:Tailwind 入口、设计变量、后台工作台、表格/表单和移动端适配。 + +### WonderQ-Admin + +```text +WonderQ-Admin/ +├─ app/ +│ ├─ main.py +│ ├─ config.py +│ ├─ database.py +│ ├─ models.py +│ ├─ schemas.py +│ ├─ auth.py +│ ├─ serializers.py +│ ├─ content.py +│ ├─ seed.py +│ └─ routers/ +│ ├─ public.py +│ ├─ admin.py +│ └─ shared.py +├─ alembic/ +├─ data/generated-products.json +├─ tests/ +├─ Dockerfile +├─ docker-compose.yml +├─ requirements.txt +├─ pyproject.toml +├─ .env.example +└─ README.md +``` + +- `app/main.py`:FastAPI 应用入口、CORS、错误处理和路由注册。 +- `app/config.py`、`app/database.py`:环境变量配置与 SQLAlchemy engine/session/Base。 +- `app/models.py`、`app/schemas.py`、`app/serializers.py`:ORM 模型、Pydantic 校验和响应序列化。 +- `app/auth.py`:JWT 与后台鉴权。 +- `app/routers/public.py`、`app/routers/admin.py`、`app/routers/shared.py`:Public API、Admin API 和共享查询。 +- `app/content.py`、`app/seed.py`、`data/generated-products.json`:初始化内容、重置命令和迁移数据源。 +- `alembic/`、`Dockerfile`、`docker-compose.yml`:数据库迁移与部署入口。 + +## 7. 启动方式 + +### 后端 `WonderQ-Admin` + +从 `WonderQ-Project` 根目录启动: + +```powershell +Set-Location .\WonderQ-Admin +.\.venv\Scripts\Activate.ps1 +docker-compose up -d postgres redis +python -m alembic upgrade head +python -m uvicorn app.main:app --host 0.0.0.0 --port 4000 --reload +``` + +首次缺少虚拟环境或依赖时,再执行: + +```powershell +python -m venv .venv +.\.venv\Scripts\Activate.ps1 +python -m pip install -r requirements.txt +``` + +健康检查:http://localhost:4000/health。 + +### 管理前端 `WonderQ-Admin-UI` + +```powershell +Set-Location .\WonderQ-Admin-UI +yarn install +yarn dev +``` + +默认访问:http://localhost:5602。后端 Admin API 默认运行在 http://localhost:4000。 + +### 前台 `WonderQ-MiniAPP` + +```powershell +Set-Location .\WonderQ-MiniAPP +yarn install +yarn dev +``` + +H5 默认访问:http://localhost:5173。微信小程序开发构建: + +```powershell +yarn dev:mp-weixin +``` + +## 8. 测试与验证 + +- `WonderQ-Admin`:修改 Python 代码后运行 `python -m pytest`;涉及迁移时运行 `python -m alembic upgrade head`;空库或 seed 相关变更才考虑 `python -m app.seed`,且执行前必须确认风险。 +- `WonderQ-Admin-UI`:当前未配置独立测试脚本,提交前至少运行 `yarn build`;涉及 UI、交互或接口行为时,本地启动页面并手动验证关键流程。 +- `WonderQ-MiniAPP`:前台变更后至少运行 `yarn build:h5`、`yarn build:mp-weixin`、`yarn test`;UI 变更还应浏览器验证移动端和桌面宽度,涉及小程序兼容时用微信开发者工具验证 `dist/build/mp-weixin`。 +- 纯文档变更可不跑构建,但必须检查文档链接、命令、路径和敏感信息。 + +## 9. 部署规范 + +- `WonderQ-MiniAPP`:H5 生产构建使用 `yarn build:h5`,产物在 `dist/build/h5`;微信小程序构建使用 `yarn build:mp-weixin`,产物在 `dist/build/mp-weixin`。 +- `WonderQ-Admin-UI`:生产发布使用 `yarn build` 生成 `dist/`,可交给 Nginx、CDN 或静态托管服务部署。 +- `WonderQ-Admin`:使用 Dockerfile 与 `docker-compose.yml` 部署 API、PostgreSQL 和 Redis。 +- 生产 API 地址、客服链接、企业 ID、JWT secret、OSS 密钥、数据库连接只允许通过部署环境变量注入,不硬编码到源码、测试或文档。 +- 不提交 `dist/`、`node_modules/`、`.venv/`、`.env`、`.env.local`、日志、coverage、数据库备份或临时规划文件。 + +## 10. 接口与数据规范 + +- Public API 与 Admin API 分离:MiniAPP 只访问 `/api/public/...`,Admin UI 只访问 `/api/admin/...`。 +- 保持现有 API 路径和响应结构兼容;不要为了统一风格擅自改路径、改字段名或改响应包裹结构。 +- 接口设计优先 RESTful 风格,如 `GET /api/admin/products`、`POST /api/admin/products`、`PATCH /api/admin/products/{id}`。 +- 禁止新增 `/getBanner`、`/saveProduct`、`/updateConfig` 这类动作式路径,除非已有契约明确要求。 +- TypeScript 与 API 响应字段保持 camelCase;后端内部可使用 snake_case,但序列化给前端时遵守契约。 +- 外部输入必须通过 Pydantic schema 或前端表单校验;后端不能信任前端传参。 +- 错误响应不得泄露内部异常、SQL、环境变量、Token、密钥或敏感业务数据。 +- 页面模块字段、排序、删除冲突、媒体上传等细节以 `module-config-api.md` 为准。 + +## 11. 数据库与后端实现原则 + +- Alembic 管理数据库迁移;涉及模型变更时同步迁移、测试和契约文档。 +- 新业务表按实际需要考虑 `id`、`created_at`、`updated_at`、`deleted_at`、`status`、`sort` 等字段,不机械添加无意义字段。 +- 时间字段后端统一使用明确时区语义;对外返回 ISO 8601 字符串。 +- 查询应合理建立索引,避免 N+1 查询和无界列表。 +- Admin 变更类接口应继续写入审计日志,尤其是发布、重置、删除、状态流转和页面配置变更。 +- 复杂新业务优先按 Router、Service、Repository 分层拆分;现有简单接口可沿用当前结构,但不要把大量业务逻辑继续堆进单个路由函数。 + +## 12. 前端实现原则 + +- TypeScript 项目使用 strict 模式,新增代码应有明确类型,避免 `any`。 +- `WonderQ-MiniAPP` 使用 Vue 3 SFC、` + + diff --git a/WonderQ-Admin-UI/package.json b/WonderQ-Admin-UI/package.json new file mode 100644 index 0000000..12960b5 --- /dev/null +++ b/WonderQ-Admin-UI/package.json @@ -0,0 +1,35 @@ +{ + "name": "wonderq-admin-ui", + "version": "0.1.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc --noEmit && vite build", + "preview": "vite preview" + }, + "dependencies": { + "@radix-ui/react-select": "^2.3.2", + "@radix-ui/react-slot": "^1.3.0", + "@radix-ui/react-switch": "^1.3.2", + "@rolldown/binding-win32-x64-msvc": "1.1.3", + "@tailwindcss/oxide-win32-x64-msvc": "4.3.2", + "@tailwindcss/vite": "^4.3.2", + "@vitejs/plugin-react": "^6.0.3", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "lightningcss-win32-x64-msvc": "1.32.0", + "lucide-react": "^1.21.0", + "react": "^19.2.7", + "react-dom": "^19.2.7", + "tailwind-merge": "^3.6.0", + "tailwindcss": "^4.3.2", + "vite": "^8.1.0" + }, + "devDependencies": { + "@types/node": "^26.0.1", + "@types/react": "^19.2.17", + "@types/react-dom": "^19.2.3", + "typescript": "^6.0.3" + } +} diff --git a/WonderQ-Admin-UI/public/assets/guizhou/baili-azalea.jpg b/WonderQ-Admin-UI/public/assets/guizhou/baili-azalea.jpg new file mode 100644 index 0000000..331e131 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/guizhou/baili-azalea.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/guizhou/bailian-hot-spring.jpg b/WonderQ-Admin-UI/public/assets/guizhou/bailian-hot-spring.jpg new file mode 100644 index 0000000..0d8f004 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/guizhou/bailian-hot-spring.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/guizhou/cave-sunbeam.jpg b/WonderQ-Admin-UI/public/assets/guizhou/cave-sunbeam.jpg new file mode 100644 index 0000000..f9c4bd3 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/guizhou/cave-sunbeam.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/guizhou/chishui-danxia.jpg b/WonderQ-Admin-UI/public/assets/guizhou/chishui-danxia.jpg new file mode 100644 index 0000000..00e4f95 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/guizhou/chishui-danxia.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/guizhou/dong-village.jpg b/WonderQ-Admin-UI/public/assets/guizhou/dong-village.jpg new file mode 100644 index 0000000..5e11592 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/guizhou/dong-village.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/guizhou/fanjing-mountain.jpg b/WonderQ-Admin-UI/public/assets/guizhou/fanjing-mountain.jpg new file mode 100644 index 0000000..ddfc76a Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/guizhou/fanjing-mountain.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/guizhou/gorge-paddle.jpg b/WonderQ-Admin-UI/public/assets/guizhou/gorge-paddle.jpg new file mode 100644 index 0000000..aa6563b Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/guizhou/gorge-paddle.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/guizhou/huangguoshu-waterfall.jpg b/WonderQ-Admin-UI/public/assets/guizhou/huangguoshu-waterfall.jpg new file mode 100644 index 0000000..1d6d035 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/guizhou/huangguoshu-waterfall.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/guizhou/intangible-masks.jpg b/WonderQ-Admin-UI/public/assets/guizhou/intangible-masks.jpg new file mode 100644 index 0000000..3e24a5d Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/guizhou/intangible-masks.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/guizhou/jiabang-terrace.jpg b/WonderQ-Admin-UI/public/assets/guizhou/jiabang-terrace.jpg new file mode 100644 index 0000000..37c8614 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/guizhou/jiabang-terrace.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/guizhou/jianhe-hot-spring.jpg b/WonderQ-Admin-UI/public/assets/guizhou/jianhe-hot-spring.jpg new file mode 100644 index 0000000..994c1b5 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/guizhou/jianhe-hot-spring.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/guizhou/jiaxiu-tower.jpg b/WonderQ-Admin-UI/public/assets/guizhou/jiaxiu-tower.jpg new file mode 100644 index 0000000..cd14edb Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/guizhou/jiaxiu-tower.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/guizhou/karst-cave-explorer.jpg b/WonderQ-Admin-UI/public/assets/guizhou/karst-cave-explorer.jpg new file mode 100644 index 0000000..1d890e1 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/guizhou/karst-cave-explorer.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/guizhou/libo-water-forest.jpg b/WonderQ-Admin-UI/public/assets/guizhou/libo-water-forest.jpg new file mode 100644 index 0000000..2263388 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/guizhou/libo-water-forest.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/guizhou/libo-xiaoqikong.jpg b/WonderQ-Admin-UI/public/assets/guizhou/libo-xiaoqikong.jpg new file mode 100644 index 0000000..5ba347f Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/guizhou/libo-xiaoqikong.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/guizhou/miao-costume.jpg b/WonderQ-Admin-UI/public/assets/guizhou/miao-costume.jpg new file mode 100644 index 0000000..7c52841 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/guizhou/miao-costume.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/guizhou/miao-dragon-boat.jpg b/WonderQ-Admin-UI/public/assets/guizhou/miao-dragon-boat.jpg new file mode 100644 index 0000000..4924d6e Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/guizhou/miao-dragon-boat.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/guizhou/miao-lusheng-dance.jpg b/WonderQ-Admin-UI/public/assets/guizhou/miao-lusheng-dance.jpg new file mode 100644 index 0000000..369f1ab Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/guizhou/miao-lusheng-dance.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/guizhou/miao-village-street.jpg b/WonderQ-Admin-UI/public/assets/guizhou/miao-village-street.jpg new file mode 100644 index 0000000..9079bd1 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/guizhou/miao-village-street.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/guizhou/mountain-resort.jpg b/WonderQ-Admin-UI/public/assets/guizhou/mountain-resort.jpg new file mode 100644 index 0000000..f185093 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/guizhou/mountain-resort.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/guizhou/shuichunhe-rafting.jpg b/WonderQ-Admin-UI/public/assets/guizhou/shuichunhe-rafting.jpg new file mode 100644 index 0000000..68b61b7 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/guizhou/shuichunhe-rafting.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/guizhou/tiankeng-pool.jpg b/WonderQ-Admin-UI/public/assets/guizhou/tiankeng-pool.jpg new file mode 100644 index 0000000..ed1383d Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/guizhou/tiankeng-pool.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/guizhou/tiankeng-sunbeam-group.jpg b/WonderQ-Admin-UI/public/assets/guizhou/tiankeng-sunbeam-group.jpg new file mode 100644 index 0000000..823f4d7 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/guizhou/tiankeng-sunbeam-group.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/guizhou/wanfenglin.jpg b/WonderQ-Admin-UI/public/assets/guizhou/wanfenglin.jpg new file mode 100644 index 0000000..01e4e76 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/guizhou/wanfenglin.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/guizhou/wumeng-grassland.jpg b/WonderQ-Admin-UI/public/assets/guizhou/wumeng-grassland.jpg new file mode 100644 index 0000000..fcbd0ea Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/guizhou/wumeng-grassland.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/guizhou/xijiang-miao-village.jpg b/WonderQ-Admin-UI/public/assets/guizhou/xijiang-miao-village.jpg new file mode 100644 index 0000000..f398b01 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/guizhou/xijiang-miao-village.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/guizhou/zhenyuan-ancient-town.jpg b/WonderQ-Admin-UI/public/assets/guizhou/zhenyuan-ancient-town.jpg new file mode 100644 index 0000000..bd8bada Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/guizhou/zhenyuan-ancient-town.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/guizhou/zhijin-cave-pool.jpg b/WonderQ-Admin-UI/public/assets/guizhou/zhijin-cave-pool.jpg new file mode 100644 index 0000000..f8aac84 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/guizhou/zhijin-cave-pool.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/guizhou/zhijin-cave.jpg b/WonderQ-Admin-UI/public/assets/guizhou/zhijin-cave.jpg new file mode 100644 index 0000000..9676ef7 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/guizhou/zhijin-cave.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-000-6130f5faf6.jpg b/WonderQ-Admin-UI/public/assets/source/asset-000-6130f5faf6.jpg new file mode 100644 index 0000000..77849f0 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-000-6130f5faf6.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-001-e3ccdf0858.jpg b/WonderQ-Admin-UI/public/assets/source/asset-001-e3ccdf0858.jpg new file mode 100644 index 0000000..dbd71e3 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-001-e3ccdf0858.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-002-60f1781bad.jpg b/WonderQ-Admin-UI/public/assets/source/asset-002-60f1781bad.jpg new file mode 100644 index 0000000..cca44c8 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-002-60f1781bad.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-003-67c94551ff.jpg b/WonderQ-Admin-UI/public/assets/source/asset-003-67c94551ff.jpg new file mode 100644 index 0000000..be3443c Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-003-67c94551ff.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-004-74801a9861.jpg b/WonderQ-Admin-UI/public/assets/source/asset-004-74801a9861.jpg new file mode 100644 index 0000000..e16e9de Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-004-74801a9861.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-005-5f88616344.jpg b/WonderQ-Admin-UI/public/assets/source/asset-005-5f88616344.jpg new file mode 100644 index 0000000..765a3c5 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-005-5f88616344.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-006-065f65e89a.png b/WonderQ-Admin-UI/public/assets/source/asset-006-065f65e89a.png new file mode 100644 index 0000000..a7562ed Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-006-065f65e89a.png differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-007-bfd23e4423.png b/WonderQ-Admin-UI/public/assets/source/asset-007-bfd23e4423.png new file mode 100644 index 0000000..66f3278 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-007-bfd23e4423.png differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-008-b69a2ebdf1.png b/WonderQ-Admin-UI/public/assets/source/asset-008-b69a2ebdf1.png new file mode 100644 index 0000000..f334075 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-008-b69a2ebdf1.png differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-009-7c60387849.png b/WonderQ-Admin-UI/public/assets/source/asset-009-7c60387849.png new file mode 100644 index 0000000..1a0bfd7 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-009-7c60387849.png differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-010-8614b34e80.png b/WonderQ-Admin-UI/public/assets/source/asset-010-8614b34e80.png new file mode 100644 index 0000000..4a9d9dc Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-010-8614b34e80.png differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-011-398553c792.png b/WonderQ-Admin-UI/public/assets/source/asset-011-398553c792.png new file mode 100644 index 0000000..13b8cf7 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-011-398553c792.png differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-012-486ac8f1a1.png b/WonderQ-Admin-UI/public/assets/source/asset-012-486ac8f1a1.png new file mode 100644 index 0000000..b373d8a Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-012-486ac8f1a1.png differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-013-babb337ba2.png b/WonderQ-Admin-UI/public/assets/source/asset-013-babb337ba2.png new file mode 100644 index 0000000..b9b6be6 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-013-babb337ba2.png differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-014-fd57beac6b.png b/WonderQ-Admin-UI/public/assets/source/asset-014-fd57beac6b.png new file mode 100644 index 0000000..603116d Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-014-fd57beac6b.png differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-015-94835fc601.png b/WonderQ-Admin-UI/public/assets/source/asset-015-94835fc601.png new file mode 100644 index 0000000..e35cdda Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-015-94835fc601.png differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-016-306236a4af.png b/WonderQ-Admin-UI/public/assets/source/asset-016-306236a4af.png new file mode 100644 index 0000000..e4d9a48 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-016-306236a4af.png differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-017-e4a0e59bd4.png b/WonderQ-Admin-UI/public/assets/source/asset-017-e4a0e59bd4.png new file mode 100644 index 0000000..0f69007 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-017-e4a0e59bd4.png differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-018-30bc451049.jpg b/WonderQ-Admin-UI/public/assets/source/asset-018-30bc451049.jpg new file mode 100644 index 0000000..f8951f5 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-018-30bc451049.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-019-8b7f71737e.jpg b/WonderQ-Admin-UI/public/assets/source/asset-019-8b7f71737e.jpg new file mode 100644 index 0000000..9ead9f3 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-019-8b7f71737e.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-020-5207a45c09.png b/WonderQ-Admin-UI/public/assets/source/asset-020-5207a45c09.png new file mode 100644 index 0000000..958e115 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-020-5207a45c09.png differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-021-267958c0d6.png b/WonderQ-Admin-UI/public/assets/source/asset-021-267958c0d6.png new file mode 100644 index 0000000..3ca51d1 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-021-267958c0d6.png differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-022-f982dcf65e.png b/WonderQ-Admin-UI/public/assets/source/asset-022-f982dcf65e.png new file mode 100644 index 0000000..b867dd0 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-022-f982dcf65e.png differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-023-20ebf544be.png b/WonderQ-Admin-UI/public/assets/source/asset-023-20ebf544be.png new file mode 100644 index 0000000..87d2fdd Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-023-20ebf544be.png differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-024-6e6ee3998c.png b/WonderQ-Admin-UI/public/assets/source/asset-024-6e6ee3998c.png new file mode 100644 index 0000000..9ae6b9b Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-024-6e6ee3998c.png differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-025-980c7ac168.png b/WonderQ-Admin-UI/public/assets/source/asset-025-980c7ac168.png new file mode 100644 index 0000000..5d34183 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-025-980c7ac168.png differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-026-6e4d686b97.png b/WonderQ-Admin-UI/public/assets/source/asset-026-6e4d686b97.png new file mode 100644 index 0000000..500a64e Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-026-6e4d686b97.png differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-027-22aef1d83b.png b/WonderQ-Admin-UI/public/assets/source/asset-027-22aef1d83b.png new file mode 100644 index 0000000..4326d0b Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-027-22aef1d83b.png differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-028-912019b131.png b/WonderQ-Admin-UI/public/assets/source/asset-028-912019b131.png new file mode 100644 index 0000000..26818f3 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-028-912019b131.png differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-029-9eccbb7131.png b/WonderQ-Admin-UI/public/assets/source/asset-029-9eccbb7131.png new file mode 100644 index 0000000..9a84338 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-029-9eccbb7131.png differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-030-a77d1ef23a.jpg b/WonderQ-Admin-UI/public/assets/source/asset-030-a77d1ef23a.jpg new file mode 100644 index 0000000..5234932 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-030-a77d1ef23a.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-031-802555e02b.png b/WonderQ-Admin-UI/public/assets/source/asset-031-802555e02b.png new file mode 100644 index 0000000..2c2b817 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-031-802555e02b.png differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-032-1257cf8865.jpg b/WonderQ-Admin-UI/public/assets/source/asset-032-1257cf8865.jpg new file mode 100644 index 0000000..7a283e0 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-032-1257cf8865.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-033-4f39bbaba6.jpg b/WonderQ-Admin-UI/public/assets/source/asset-033-4f39bbaba6.jpg new file mode 100644 index 0000000..585c94b Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-033-4f39bbaba6.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-034-393944f522.png b/WonderQ-Admin-UI/public/assets/source/asset-034-393944f522.png new file mode 100644 index 0000000..2cf1d79 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-034-393944f522.png differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-035-9d6bac22b3.jpg b/WonderQ-Admin-UI/public/assets/source/asset-035-9d6bac22b3.jpg new file mode 100644 index 0000000..ae2d64a Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-035-9d6bac22b3.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-036-60d6309202.jpg b/WonderQ-Admin-UI/public/assets/source/asset-036-60d6309202.jpg new file mode 100644 index 0000000..10ac4a2 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-036-60d6309202.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-037-b6dee37086.jpg b/WonderQ-Admin-UI/public/assets/source/asset-037-b6dee37086.jpg new file mode 100644 index 0000000..7c006a9 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-037-b6dee37086.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-038-90f983ea37.jpg b/WonderQ-Admin-UI/public/assets/source/asset-038-90f983ea37.jpg new file mode 100644 index 0000000..a89fb16 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-038-90f983ea37.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-039-a02a731cec.jpg b/WonderQ-Admin-UI/public/assets/source/asset-039-a02a731cec.jpg new file mode 100644 index 0000000..d99ef2d Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-039-a02a731cec.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-040-10c33d1558.jpg b/WonderQ-Admin-UI/public/assets/source/asset-040-10c33d1558.jpg new file mode 100644 index 0000000..ec4b01d Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-040-10c33d1558.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-041-c5a7b61b99.jpg b/WonderQ-Admin-UI/public/assets/source/asset-041-c5a7b61b99.jpg new file mode 100644 index 0000000..c3eb5c8 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-041-c5a7b61b99.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-042-263c1d8958.jpg b/WonderQ-Admin-UI/public/assets/source/asset-042-263c1d8958.jpg new file mode 100644 index 0000000..4f1e158 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-042-263c1d8958.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-043-a1bbc0007e.jpg b/WonderQ-Admin-UI/public/assets/source/asset-043-a1bbc0007e.jpg new file mode 100644 index 0000000..cd41590 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-043-a1bbc0007e.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-044-80ccc16363.jpg b/WonderQ-Admin-UI/public/assets/source/asset-044-80ccc16363.jpg new file mode 100644 index 0000000..9fe4396 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-044-80ccc16363.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-045-014a557086.png b/WonderQ-Admin-UI/public/assets/source/asset-045-014a557086.png new file mode 100644 index 0000000..ea44d60 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-045-014a557086.png differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-046-5b4ca8173b.png b/WonderQ-Admin-UI/public/assets/source/asset-046-5b4ca8173b.png new file mode 100644 index 0000000..63a6db0 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-046-5b4ca8173b.png differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-047-14415ef235.jpg b/WonderQ-Admin-UI/public/assets/source/asset-047-14415ef235.jpg new file mode 100644 index 0000000..46e987b Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-047-14415ef235.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-048-cdb636ea72.jpg b/WonderQ-Admin-UI/public/assets/source/asset-048-cdb636ea72.jpg new file mode 100644 index 0000000..5ce3511 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-048-cdb636ea72.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-049-662d6cd220.jpg b/WonderQ-Admin-UI/public/assets/source/asset-049-662d6cd220.jpg new file mode 100644 index 0000000..d30baa8 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-049-662d6cd220.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-050-b1dcc1ad8e.jpg b/WonderQ-Admin-UI/public/assets/source/asset-050-b1dcc1ad8e.jpg new file mode 100644 index 0000000..d0fec59 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-050-b1dcc1ad8e.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-051-5873b802e1.jpg b/WonderQ-Admin-UI/public/assets/source/asset-051-5873b802e1.jpg new file mode 100644 index 0000000..a7b9051 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-051-5873b802e1.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-052-8454c19a8f.jpg b/WonderQ-Admin-UI/public/assets/source/asset-052-8454c19a8f.jpg new file mode 100644 index 0000000..0ea69d9 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-052-8454c19a8f.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-053-9298156002.jpg b/WonderQ-Admin-UI/public/assets/source/asset-053-9298156002.jpg new file mode 100644 index 0000000..8407efc Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-053-9298156002.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-054-c936b44502.jpg b/WonderQ-Admin-UI/public/assets/source/asset-054-c936b44502.jpg new file mode 100644 index 0000000..f1cdd81 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-054-c936b44502.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-055-0cd651d9e1.jpg b/WonderQ-Admin-UI/public/assets/source/asset-055-0cd651d9e1.jpg new file mode 100644 index 0000000..71e9e8e Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-055-0cd651d9e1.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-056-209a8a139f.jpg b/WonderQ-Admin-UI/public/assets/source/asset-056-209a8a139f.jpg new file mode 100644 index 0000000..674dab7 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-056-209a8a139f.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-057-7c54fd675c.jpg b/WonderQ-Admin-UI/public/assets/source/asset-057-7c54fd675c.jpg new file mode 100644 index 0000000..6eaf2f5 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-057-7c54fd675c.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-058-77303eee5e.jpg b/WonderQ-Admin-UI/public/assets/source/asset-058-77303eee5e.jpg new file mode 100644 index 0000000..39b5b2b Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-058-77303eee5e.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-059-a8a6b2886f.jpg b/WonderQ-Admin-UI/public/assets/source/asset-059-a8a6b2886f.jpg new file mode 100644 index 0000000..7157652 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-059-a8a6b2886f.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-060-4906700f3d.jpg b/WonderQ-Admin-UI/public/assets/source/asset-060-4906700f3d.jpg new file mode 100644 index 0000000..d5cc59c Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-060-4906700f3d.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-061-34916cd0eb.jpg b/WonderQ-Admin-UI/public/assets/source/asset-061-34916cd0eb.jpg new file mode 100644 index 0000000..b387f42 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-061-34916cd0eb.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-062-d0571e4731.jpg b/WonderQ-Admin-UI/public/assets/source/asset-062-d0571e4731.jpg new file mode 100644 index 0000000..96c360a Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-062-d0571e4731.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-063-b8f12a7d43.jpg b/WonderQ-Admin-UI/public/assets/source/asset-063-b8f12a7d43.jpg new file mode 100644 index 0000000..754dcf9 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-063-b8f12a7d43.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-064-3f85c3a4e7.jpg b/WonderQ-Admin-UI/public/assets/source/asset-064-3f85c3a4e7.jpg new file mode 100644 index 0000000..9798891 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-064-3f85c3a4e7.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-065-48df4407bc.jpg b/WonderQ-Admin-UI/public/assets/source/asset-065-48df4407bc.jpg new file mode 100644 index 0000000..0b5ee57 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-065-48df4407bc.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-066-a3f2f1272a.jpg b/WonderQ-Admin-UI/public/assets/source/asset-066-a3f2f1272a.jpg new file mode 100644 index 0000000..7b5ce3f Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-066-a3f2f1272a.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-067-447266ec79.jpg b/WonderQ-Admin-UI/public/assets/source/asset-067-447266ec79.jpg new file mode 100644 index 0000000..5dd12c9 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-067-447266ec79.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-068-3d774150b9.jpg b/WonderQ-Admin-UI/public/assets/source/asset-068-3d774150b9.jpg new file mode 100644 index 0000000..c8b0347 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-068-3d774150b9.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-069-90ae10dc55.jpg b/WonderQ-Admin-UI/public/assets/source/asset-069-90ae10dc55.jpg new file mode 100644 index 0000000..035c350 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-069-90ae10dc55.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-070-2d9f8846d1.jpg b/WonderQ-Admin-UI/public/assets/source/asset-070-2d9f8846d1.jpg new file mode 100644 index 0000000..eea2692 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-070-2d9f8846d1.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-071-1cd6938258.jpg b/WonderQ-Admin-UI/public/assets/source/asset-071-1cd6938258.jpg new file mode 100644 index 0000000..feafa05 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-071-1cd6938258.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-072-65f094370f.jpg b/WonderQ-Admin-UI/public/assets/source/asset-072-65f094370f.jpg new file mode 100644 index 0000000..0e55c60 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-072-65f094370f.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-073-50718eaa04.jpg b/WonderQ-Admin-UI/public/assets/source/asset-073-50718eaa04.jpg new file mode 100644 index 0000000..1a98783 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-073-50718eaa04.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-074-27e8eeb978.jpg b/WonderQ-Admin-UI/public/assets/source/asset-074-27e8eeb978.jpg new file mode 100644 index 0000000..55d20e2 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-074-27e8eeb978.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-075-21da2203d7.jpg b/WonderQ-Admin-UI/public/assets/source/asset-075-21da2203d7.jpg new file mode 100644 index 0000000..566891c Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-075-21da2203d7.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-076-df483f164e.jpg b/WonderQ-Admin-UI/public/assets/source/asset-076-df483f164e.jpg new file mode 100644 index 0000000..c260204 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-076-df483f164e.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-077-10074b62a0.jpg b/WonderQ-Admin-UI/public/assets/source/asset-077-10074b62a0.jpg new file mode 100644 index 0000000..c96de1b Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-077-10074b62a0.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-078-5a8b1d3faf.jpg b/WonderQ-Admin-UI/public/assets/source/asset-078-5a8b1d3faf.jpg new file mode 100644 index 0000000..9d25bb3 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-078-5a8b1d3faf.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-079-b87c2aebbc.jpg b/WonderQ-Admin-UI/public/assets/source/asset-079-b87c2aebbc.jpg new file mode 100644 index 0000000..c91e3bb Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-079-b87c2aebbc.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-080-e26f5fd1af.jpg b/WonderQ-Admin-UI/public/assets/source/asset-080-e26f5fd1af.jpg new file mode 100644 index 0000000..cce74cb Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-080-e26f5fd1af.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-081-f8ed32e871.jpg b/WonderQ-Admin-UI/public/assets/source/asset-081-f8ed32e871.jpg new file mode 100644 index 0000000..306a25a Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-081-f8ed32e871.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-082-7265272fc7.jpg b/WonderQ-Admin-UI/public/assets/source/asset-082-7265272fc7.jpg new file mode 100644 index 0000000..9ed410a Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-082-7265272fc7.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-083-5a645cf860.jpg b/WonderQ-Admin-UI/public/assets/source/asset-083-5a645cf860.jpg new file mode 100644 index 0000000..88ec008 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-083-5a645cf860.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-084-e9e0000a3f.jpg b/WonderQ-Admin-UI/public/assets/source/asset-084-e9e0000a3f.jpg new file mode 100644 index 0000000..4415295 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-084-e9e0000a3f.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-085-bb1263df56.jpg b/WonderQ-Admin-UI/public/assets/source/asset-085-bb1263df56.jpg new file mode 100644 index 0000000..a04f228 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-085-bb1263df56.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-086-8a8d225934.jpg b/WonderQ-Admin-UI/public/assets/source/asset-086-8a8d225934.jpg new file mode 100644 index 0000000..c3d4fb6 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-086-8a8d225934.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-087-b290f942f6.jpg b/WonderQ-Admin-UI/public/assets/source/asset-087-b290f942f6.jpg new file mode 100644 index 0000000..505e6f7 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-087-b290f942f6.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-088-4836acf6df.jpg b/WonderQ-Admin-UI/public/assets/source/asset-088-4836acf6df.jpg new file mode 100644 index 0000000..9807b06 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-088-4836acf6df.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-089-970bccb170.jpg b/WonderQ-Admin-UI/public/assets/source/asset-089-970bccb170.jpg new file mode 100644 index 0000000..6f50363 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-089-970bccb170.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-090-94e7f5f26f.png b/WonderQ-Admin-UI/public/assets/source/asset-090-94e7f5f26f.png new file mode 100644 index 0000000..5185131 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-090-94e7f5f26f.png differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-091-9dcce2d1f9.jpg b/WonderQ-Admin-UI/public/assets/source/asset-091-9dcce2d1f9.jpg new file mode 100644 index 0000000..7bfe00b Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-091-9dcce2d1f9.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-092-6d447dfa4e.jpg b/WonderQ-Admin-UI/public/assets/source/asset-092-6d447dfa4e.jpg new file mode 100644 index 0000000..69ac7ce Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-092-6d447dfa4e.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-093-1d8b7d743b.jpg b/WonderQ-Admin-UI/public/assets/source/asset-093-1d8b7d743b.jpg new file mode 100644 index 0000000..77d8755 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-093-1d8b7d743b.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-094-506564ecb7.jpg b/WonderQ-Admin-UI/public/assets/source/asset-094-506564ecb7.jpg new file mode 100644 index 0000000..32149f3 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-094-506564ecb7.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/asset-095-bd37c3754d.jpg b/WonderQ-Admin-UI/public/assets/source/asset-095-bd37c3754d.jpg new file mode 100644 index 0000000..b6efae8 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/asset-095-bd37c3754d.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/manifest.json b/WonderQ-Admin-UI/public/assets/source/manifest.json new file mode 100644 index 0000000..7f6140c --- /dev/null +++ b/WonderQ-Admin-UI/public/assets/source/manifest.json @@ -0,0 +1,869 @@ +{ + "generatedAt": "2026-06-25T03:21:05.867Z", + "assets": [ + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0301k12000smvj7fr86BF_Q80.jpg?proc=format%2Ff_webp%3Bcorp%2Ft163", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 170388, + "filename": "asset-000-6130f5faf6.jpg", + "publicPath": "/assets/source/asset-000-6130f5faf6.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0305t12000sb9yawgA680_Q80.jpg?proc=format%2Ff_webp%3Bcorp%2Ft163", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 212456, + "filename": "asset-001-e3ccdf0858.jpg", + "publicPath": "/assets/source/asset-001-e3ccdf0858.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0304812000slb8alx3F3F_Q80.jpg?proc=format%2Ff_webp%3Bcorp%2Ft163", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 91178, + "filename": "asset-002-60f1781bad.jpg", + "publicPath": "/assets/source/asset-002-60f1781bad.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0304p12000smeitomC5EE_Q80.jpg?proc=format%2Ff_webp%3Bcorp%2Ft163", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 284254, + "filename": "asset-003-67c94551ff.jpg", + "publicPath": "/assets/source/asset-003-67c94551ff.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0303l12000smeikth375E_Q80.jpg?proc=format%2Ff_webp%3Bcorp%2Ft163", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 271294, + "filename": "asset-004-74801a9861.jpg", + "publicPath": "/assets/source/asset-004-74801a9861.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0306v12000smeini5EBB8_Q80.jpg?proc=format%2Ff_webp%3Bcorp%2Ft163", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 241168, + "filename": "asset-005-5f88616344.jpg", + "publicPath": "/assets/source/asset-005-5f88616344.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0300l12000izkd2vhADDB_Q80.png?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 3098, + "filename": "asset-006-065f65e89a.png", + "publicPath": "/assets/source/asset-006-065f65e89a.png" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0300y12000izkd78l8AD7_Q80.png?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 1638, + "filename": "asset-007-bfd23e4423.png", + "publicPath": "/assets/source/asset-007-bfd23e4423.png" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0300412000izkedzdBEE1_Q80.png?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 2026, + "filename": "asset-008-b69a2ebdf1.png", + "publicPath": "/assets/source/asset-008-b69a2ebdf1.png" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0305k12000j0ka6gt8771_Q80.png?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 882, + "filename": "asset-009-7c60387849.png", + "publicPath": "/assets/source/asset-009-7c60387849.png" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0303712000izkddq5FD05_Q80.png?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 1938, + "filename": "asset-010-8614b34e80.png", + "publicPath": "/assets/source/asset-010-8614b34e80.png" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0305h12000sorwqyf8CF6_Q80.png?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 8248, + "filename": "asset-011-398553c792.png", + "publicPath": "/assets/source/asset-011-398553c792.png" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0301412000sorwcsjFC42_Q80.png?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 7998, + "filename": "asset-012-486ac8f1a1.png", + "publicPath": "/assets/source/asset-012-486ac8f1a1.png" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0304n12000sorx2ot95E2_Q80.png?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 10282, + "filename": "asset-013-babb337ba2.png", + "publicPath": "/assets/source/asset-013-babb337ba2.png" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0301g12000sorxk921BDB_Q80.png?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 9266, + "filename": "asset-014-fd57beac6b.png", + "publicPath": "/assets/source/asset-014-fd57beac6b.png" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0302y12000sorxrncD367_Q80.png?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 10524, + "filename": "asset-015-94835fc601.png", + "publicPath": "/assets/source/asset-015-94835fc601.png" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0304s12000soryjcp2123_Q80.png?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 6178, + "filename": "asset-016-306236a4af.png", + "publicPath": "/assets/source/asset-016-306236a4af.png" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0306h12000sory9nl55CA_Q80.png?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 10098, + "filename": "asset-017-e4a0e59bd4.png", + "publicPath": "/assets/source/asset-017-e4a0e59bd4.png" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0303p12000f9vpbs2E0CC_Q80.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 13620, + "filename": "asset-018-30bc451049.jpg", + "publicPath": "/assets/source/asset-018-30bc451049.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0306e12000kwyklve849A_Q80.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 12854, + "filename": "asset-019-8b7f71737e.jpg", + "publicPath": "/assets/source/asset-019-8b7f71737e.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0301c12000j0jomub6A63_Q80.png?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 11474, + "filename": "asset-020-5207a45c09.png", + "publicPath": "/assets/source/asset-020-5207a45c09.png" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0300i12000j0jowt4F1F0_Q80.png?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 12382, + "filename": "asset-021-267958c0d6.png", + "publicPath": "/assets/source/asset-021-267958c0d6.png" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0303t12000irw2m6tBEB9_Q80.png?proc=format%2Ff_webp%3Bresize%2Fm_c%2Cw_1125%2Ch_858%3Bcrop%2Fm_c%2Cw_1125%2Ch_450%2Cx_0%2Cy_0%2CF1B8", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 30698, + "filename": "asset-022-f982dcf65e.png", + "publicPath": "/assets/source/asset-022-f982dcf65e.png" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0303t12000irw2m6tBEB9_Q80.png?proc=format%2Ff_webp%3Bresize%2Fm_c%2Cw_1125%2Ch_858%3Bcrop%2Fm_c%2Cw_1125%2Ch_450%2Cx_0%2Cy_450%2CE74F", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 18064, + "filename": "asset-023-20ebf544be.png", + "publicPath": "/assets/source/asset-023-20ebf544be.png" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/1tw2s12000ii40grfF6DE.png", + "ok": true, + "status": 200, + "contentType": "image/png", + "bytes": 1471, + "filename": "asset-024-6e6ee3998c.png", + "publicPath": "/assets/source/asset-024-6e6ee3998c.png" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/1tw6x12000ii41qst9B8C.png", + "ok": true, + "status": 200, + "contentType": "image/png", + "bytes": 1139, + "filename": "asset-025-980c7ac168.png", + "publicPath": "/assets/source/asset-025-980c7ac168.png" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/1tw1d12000ii3zremDD90.png", + "ok": true, + "status": 200, + "contentType": "image/png", + "bytes": 497, + "filename": "asset-026-6e4d686b97.png", + "publicPath": "/assets/source/asset-026-6e4d686b97.png" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/1tw2q12000ii3z57n9203.png", + "ok": true, + "status": 200, + "contentType": "image/png", + "bytes": 703, + "filename": "asset-027-22aef1d83b.png", + "publicPath": "/assets/source/asset-027-22aef1d83b.png" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0300512000irztxfa30DB_Q80.png", + "ok": true, + "status": 200, + "contentType": "image/png", + "bytes": 68584, + "filename": "asset-028-912019b131.png", + "publicPath": "/assets/source/asset-028-912019b131.png" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0306y12000irytaffD93C_Q80.png", + "ok": true, + "status": 200, + "contentType": "image/png", + "bytes": 67709, + "filename": "asset-029-9eccbb7131.png", + "publicPath": "/assets/source/asset-029-9eccbb7131.png" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0306v12000s0usa7gF64D_C_265_265.jpg", + "ok": true, + "status": 200, + "contentType": "image/jpeg", + "bytes": 12465, + "filename": "asset-030-a77d1ef23a.jpg", + "publicPath": "/assets/source/asset-030-a77d1ef23a.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0300p12000q01uwt3ECA7_C_265_265_Q80.png", + "ok": true, + "status": 200, + "contentType": "image/png", + "bytes": 161758, + "filename": "asset-031-802555e02b.png", + "publicPath": "/assets/source/asset-031-802555e02b.png" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0305a12000s38bp9m41BB_C_265_265.jpg", + "ok": true, + "status": 200, + "contentType": "image/jpeg", + "bytes": 16056, + "filename": "asset-032-1257cf8865.jpg", + "publicPath": "/assets/source/asset-032-1257cf8865.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0306412000smvvyxs06F1_C_265_265.jpg", + "ok": true, + "status": 200, + "contentType": "image/jpeg", + "bytes": 13094, + "filename": "asset-033-4f39bbaba6.jpg", + "publicPath": "/assets/source/asset-033-4f39bbaba6.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0305712000irzq2lgA6B7_C_265_265_Q80.png", + "ok": true, + "status": 200, + "contentType": "image/png", + "bytes": 152439, + "filename": "asset-034-393944f522.png", + "publicPath": "/assets/source/asset-034-393944f522.png" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0301612000s0uuuet873F_C_265_265.jpg", + "ok": true, + "status": 200, + "contentType": "image/jpeg", + "bytes": 13779, + "filename": "asset-035-9d6bac22b3.jpg", + "publicPath": "/assets/source/asset-035-9d6bac22b3.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0301712000rqs98cfB2AD_C_265_265.jpg", + "ok": true, + "status": 200, + "contentType": "image/jpeg", + "bytes": 11943, + "filename": "asset-036-60d6309202.jpg", + "publicPath": "/assets/source/asset-036-60d6309202.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0305h12000rqs8te62765_C_265_265.jpg", + "ok": true, + "status": 200, + "contentType": "image/jpeg", + "bytes": 14173, + "filename": "asset-037-b6dee37086.jpg", + "publicPath": "/assets/source/asset-037-b6dee37086.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0301412000krauoilC5D4.jpg?proc=format%2Ff_webp%3Bresize%2Fm_w%2Cw_258%2Ch_541%2CFE25", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 16470, + "filename": "asset-038-90f983ea37.jpg", + "publicPath": "/assets/source/asset-038-90f983ea37.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0307412000qv8ly1g77F7.jpg?proc=format%2Ff_webp%3Bresize%2Fm_w%2Cw_258%2Ch_541%2CFE25", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 11538, + "filename": "asset-039-a02a731cec.jpg", + "publicPath": "/assets/source/asset-039-a02a731cec.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0305112000krauo6x3C1E.jpg?proc=format%2Ff_webp%3Bresize%2Fm_w%2Cw_258%2Ch_541%2CFE25", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 13756, + "filename": "asset-040-10c33d1558.jpg", + "publicPath": "/assets/source/asset-040-10c33d1558.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0306q12000slbab6t7D10.jpg?proc=format%2Ff_webp%3Bresize%2Fm_w%2Cw_258%2Ch_541%2CFE25", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 11232, + "filename": "asset-041-c5a7b61b99.jpg", + "publicPath": "/assets/source/asset-041-c5a7b61b99.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0302h12000s6djf1bB21E.jpg?proc=format%2Ff_webp%3Bresize%2Fm_w%2Cw_258%2Ch_541%2CFE25", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 12106, + "filename": "asset-042-263c1d8958.jpg", + "publicPath": "/assets/source/asset-042-263c1d8958.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0300q12000qfa9e5t4957.jpg?proc=format%2Ff_webp%3Bresize%2Fm_w%2Cw_258%2Ch_541%2CFE25", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 13112, + "filename": "asset-043-a1bbc0007e.jpg", + "publicPath": "/assets/source/asset-043-a1bbc0007e.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0306312000kraurrg4784.jpg?proc=format%2Ff_webp%3Bresize%2Fm_w%2Cw_258%2Ch_541%2CFE25", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 17192, + "filename": "asset-044-80ccc16363.jpg", + "publicPath": "/assets/source/asset-044-80ccc16363.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0303g12000irmavs698BD_Q80.png?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 38990, + "filename": "asset-045-014a557086.png", + "publicPath": "/assets/source/asset-045-014a557086.png" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0305512000j0hhbvn7E21_Q80.png?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 766, + "filename": "asset-046-5b4ca8173b.png", + "publicPath": "/assets/source/asset-046-5b4ca8173b.png" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/3C071e000001fmkft5B48_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 90922, + "filename": "asset-047-14415ef235.jpg", + "publicPath": "/assets/source/asset-047-14415ef235.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C5r12000jchfwqqCBA0_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 27202, + "filename": "asset-048-cdb636ea72.jpg", + "publicPath": "/assets/source/asset-048-cdb636ea72.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C0612000sb7jwk12CFB_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 31806, + "filename": "asset-049-662d6cd220.jpg", + "publicPath": "/assets/source/asset-049-662d6cd220.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C4d12000cs3gt370743_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 34978, + "filename": "asset-050-b1dcc1ad8e.jpg", + "publicPath": "/assets/source/asset-050-b1dcc1ad8e.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/3C0k1e000001fakda86E2_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 36024, + "filename": "asset-051-5873b802e1.jpg", + "publicPath": "/assets/source/asset-051-5873b802e1.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C6j12000bttek05089C_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 14534, + "filename": "asset-052-8454c19a8f.jpg", + "publicPath": "/assets/source/asset-052-8454c19a8f.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C0k12000a65nz928183_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 27006, + "filename": "asset-053-9298156002.jpg", + "publicPath": "/assets/source/asset-053-9298156002.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C6w12000s96wqaf365D_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 49792, + "filename": "asset-054-c936b44502.jpg", + "publicPath": "/assets/source/asset-054-c936b44502.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C5n12000rxi0cdaF5A6_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 24212, + "filename": "asset-055-0cd651d9e1.jpg", + "publicPath": "/assets/source/asset-055-0cd651d9e1.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C0712000ctfu55q089F_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 32388, + "filename": "asset-056-209a8a139f.jpg", + "publicPath": "/assets/source/asset-056-209a8a139f.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C3812000rf8djcf4023_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 15626, + "filename": "asset-057-7c54fd675c.jpg", + "publicPath": "/assets/source/asset-057-7c54fd675c.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C6z120009v8609gE0D1_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 15670, + "filename": "asset-058-77303eee5e.jpg", + "publicPath": "/assets/source/asset-058-77303eee5e.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C1j12000resqsm3DE93_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 51726, + "filename": "asset-059-a8a6b2886f.jpg", + "publicPath": "/assets/source/asset-059-a8a6b2886f.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C6s12000s7x1adoA25F_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 51990, + "filename": "asset-060-4906700f3d.jpg", + "publicPath": "/assets/source/asset-060-4906700f3d.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/3C0w1e000001f33gd0E57_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 33882, + "filename": "asset-061-34916cd0eb.jpg", + "publicPath": "/assets/source/asset-061-34916cd0eb.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C0s120009mut1bo4227_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 18032, + "filename": "asset-062-d0571e4731.jpg", + "publicPath": "/assets/source/asset-062-d0571e4731.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C0u12000rt3ga88866B_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 50592, + "filename": "asset-063-b8f12a7d43.jpg", + "publicPath": "/assets/source/asset-063-b8f12a7d43.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C6512000pjf6rgp9B46_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 73024, + "filename": "asset-064-3f85c3a4e7.jpg", + "publicPath": "/assets/source/asset-064-3f85c3a4e7.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C44120009np9rh540C0_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 24688, + "filename": "asset-065-48df4407bc.jpg", + "publicPath": "/assets/source/asset-065-48df4407bc.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C0z12000sg0gi4u734E_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 29600, + "filename": "asset-066-a3f2f1272a.jpg", + "publicPath": "/assets/source/asset-066-a3f2f1272a.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C3p12000sjhokqgE5A4_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 23620, + "filename": "asset-067-447266ec79.jpg", + "publicPath": "/assets/source/asset-067-447266ec79.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C1112000rzwt90j3652_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 45030, + "filename": "asset-068-3d774150b9.jpg", + "publicPath": "/assets/source/asset-068-3d774150b9.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C3912000r7u3e6d7AFC_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 30012, + "filename": "asset-069-90ae10dc55.jpg", + "publicPath": "/assets/source/asset-069-90ae10dc55.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C4v12000sny387lAC23_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 64618, + "filename": "asset-070-2d9f8846d1.jpg", + "publicPath": "/assets/source/asset-070-2d9f8846d1.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C2012000f6dg8h09EDD_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 17094, + "filename": "asset-071-1cd6938258.jpg", + "publicPath": "/assets/source/asset-071-1cd6938258.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C1x12000rx4uno998FF_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 42246, + "filename": "asset-072-65f094370f.jpg", + "publicPath": "/assets/source/asset-072-65f094370f.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C4s12000espf8b9A9F7_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 48174, + "filename": "asset-073-50718eaa04.jpg", + "publicPath": "/assets/source/asset-073-50718eaa04.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C2n12000bk6ypzh1B0A_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 36482, + "filename": "asset-074-27e8eeb978.jpg", + "publicPath": "/assets/source/asset-074-27e8eeb978.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C1w12000pkzp4vrE479_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 16582, + "filename": "asset-075-21da2203d7.jpg", + "publicPath": "/assets/source/asset-075-21da2203d7.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C3112000cl7p7d8965C_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 20602, + "filename": "asset-076-df483f164e.jpg", + "publicPath": "/assets/source/asset-076-df483f164e.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/3C0d1e000001ewqeaAD63_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 27194, + "filename": "asset-077-10074b62a0.jpg", + "publicPath": "/assets/source/asset-077-10074b62a0.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C5g12000dn1gi668F11_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 13926, + "filename": "asset-078-5a8b1d3faf.jpg", + "publicPath": "/assets/source/asset-078-5a8b1d3faf.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C3h12000hm73r7kF70A_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 22920, + "filename": "asset-079-b87c2aebbc.jpg", + "publicPath": "/assets/source/asset-079-b87c2aebbc.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C1812000hzlez253E06_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 41918, + "filename": "asset-080-e26f5fd1af.jpg", + "publicPath": "/assets/source/asset-080-e26f5fd1af.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C6p12000f1qtq7l0D78_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 41134, + "filename": "asset-081-f8ed32e871.jpg", + "publicPath": "/assets/source/asset-081-f8ed32e871.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C0z12000rwkb013F312_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 30154, + "filename": "asset-082-7265272fc7.jpg", + "publicPath": "/assets/source/asset-082-7265272fc7.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C3o12000atd38jj839B_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 33950, + "filename": "asset-083-5a645cf860.jpg", + "publicPath": "/assets/source/asset-083-5a645cf860.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C5d12000rbyq0eeA5CB_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 38516, + "filename": "asset-084-e9e0000a3f.jpg", + "publicPath": "/assets/source/asset-084-e9e0000a3f.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C5q12000qysig6h1197_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 27044, + "filename": "asset-085-bb1263df56.jpg", + "publicPath": "/assets/source/asset-085-bb1263df56.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/3C0j1e000001exo9f0BDE_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 27422, + "filename": "asset-086-8a8d225934.jpg", + "publicPath": "/assets/source/asset-086-8a8d225934.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C1212000seh6r0k668B_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 39556, + "filename": "asset-087-b290f942f6.jpg", + "publicPath": "/assets/source/asset-087-b290f942f6.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/03C2r12000azwjkm83256_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 32184, + "filename": "asset-088-4836acf6df.jpg", + "publicPath": "/assets/source/asset-088-4836acf6df.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/3C091e000001f085j4CB6_C_548_348.jpg?proc=format%2Ff_webp", + "ok": true, + "status": 200, + "contentType": "image/webp", + "bytes": 34382, + "filename": "asset-089-970bccb170.jpg", + "publicPath": "/assets/source/asset-089-970bccb170.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0301512000iru41stFB96_Q80.png", + "ok": true, + "status": 200, + "contentType": "image/png", + "bytes": 679975, + "filename": "asset-090-94e7f5f26f.png", + "publicPath": "/assets/source/asset-090-94e7f5f26f.png" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0300d12000jwawcibEF59.jpg", + "ok": true, + "status": 200, + "contentType": "image/jpeg", + "bytes": 154367, + "filename": "asset-091-9dcce2d1f9.jpg", + "publicPath": "/assets/source/asset-091-9dcce2d1f9.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0304c12000j1294oeB9BC.jpg", + "ok": true, + "status": 200, + "contentType": "image/jpeg", + "bytes": 143987, + "filename": "asset-092-6d447dfa4e.jpg", + "publicPath": "/assets/source/asset-092-6d447dfa4e.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0303p12000j12afin35D8.jpg", + "ok": true, + "status": 200, + "contentType": "image/jpeg", + "bytes": 179667, + "filename": "asset-093-1d8b7d743b.jpg", + "publicPath": "/assets/source/asset-093-1d8b7d743b.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0303e12000j2nt1i62B74.jpg", + "ok": true, + "status": 200, + "contentType": "image/jpeg", + "bytes": 169045, + "filename": "asset-094-506564ecb7.jpg", + "publicPath": "/assets/source/asset-094-506564ecb7.jpg" + }, + { + "originalUrl": "https://dimg04.c-ctrip.com/images/0305h12000msz4nbxC853.jpg", + "ok": true, + "status": 200, + "contentType": "image/jpeg", + "bytes": 424627, + "filename": "asset-095-bd37c3754d.jpg", + "publicPath": "/assets/source/asset-095-bd37c3754d.jpg" + } + ] +} \ No newline at end of file diff --git a/WonderQ-Admin-UI/public/assets/source/secondary-bali-2de0f08eaa.jpg b/WonderQ-Admin-UI/public/assets/source/secondary-bali-2de0f08eaa.jpg new file mode 100644 index 0000000..1d51bde Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/secondary-bali-2de0f08eaa.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/secondary-domestic-icon-a263c9ffe7.png b/WonderQ-Admin-UI/public/assets/source/secondary-domestic-icon-a263c9ffe7.png new file mode 100644 index 0000000..e9ccb4b Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/secondary-domestic-icon-a263c9ffe7.png differ diff --git a/WonderQ-Admin-UI/public/assets/source/secondary-fiji-b742a38ceb.jpg b/WonderQ-Admin-UI/public/assets/source/secondary-fiji-b742a38ceb.jpg new file mode 100644 index 0000000..d5e5848 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/secondary-fiji-b742a38ceb.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/secondary-france-41bf852d5e.jpg b/WonderQ-Admin-UI/public/assets/source/secondary-france-41bf852d5e.jpg new file mode 100644 index 0000000..071bd22 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/secondary-france-41bf852d5e.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/secondary-gansu-0a92435395.jpg b/WonderQ-Admin-UI/public/assets/source/secondary-gansu-0a92435395.jpg new file mode 100644 index 0000000..d8f0589 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/secondary-gansu-0a92435395.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/secondary-kenya-1c2c61d13a.jpg b/WonderQ-Admin-UI/public/assets/source/secondary-kenya-1c2c61d13a.jpg new file mode 100644 index 0000000..1da8380 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/secondary-kenya-1c2c61d13a.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/secondary-maldives-283b20785e.jpg b/WonderQ-Admin-UI/public/assets/source/secondary-maldives-283b20785e.jpg new file mode 100644 index 0000000..47e4afd Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/secondary-maldives-283b20785e.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/secondary-norway-524e1598a1.jpg b/WonderQ-Admin-UI/public/assets/source/secondary-norway-524e1598a1.jpg new file mode 100644 index 0000000..c180850 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/secondary-norway-524e1598a1.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/secondary-outbound-icon-560ad58d3c.png b/WonderQ-Admin-UI/public/assets/source/secondary-outbound-icon-560ad58d3c.png new file mode 100644 index 0000000..b787f84 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/secondary-outbound-icon-560ad58d3c.png differ diff --git a/WonderQ-Admin-UI/public/assets/source/secondary-saudi-1b47ef583a.jpg b/WonderQ-Admin-UI/public/assets/source/secondary-saudi-1b47ef583a.jpg new file mode 100644 index 0000000..cc6682d Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/secondary-saudi-1b47ef583a.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/secondary-singapore-bcda6d9f5f.jpg b/WonderQ-Admin-UI/public/assets/source/secondary-singapore-bcda6d9f5f.jpg new file mode 100644 index 0000000..2f51332 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/secondary-singapore-bcda6d9f5f.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/secondary-srilanka-659c7fa697.jpg b/WonderQ-Admin-UI/public/assets/source/secondary-srilanka-659c7fa697.jpg new file mode 100644 index 0000000..e668ea3 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/secondary-srilanka-659c7fa697.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/secondary-tanzania-d607ec8990.jpg b/WonderQ-Admin-UI/public/assets/source/secondary-tanzania-d607ec8990.jpg new file mode 100644 index 0000000..66ffbd0 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/secondary-tanzania-d607ec8990.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/secondary-thailand-e9aa2cae4e.jpg b/WonderQ-Admin-UI/public/assets/source/secondary-thailand-e9aa2cae4e.jpg new file mode 100644 index 0000000..b312ab7 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/secondary-thailand-e9aa2cae4e.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/secondary-uk-37d1647a7d.jpg b/WonderQ-Admin-UI/public/assets/source/secondary-uk-37d1647a7d.jpg new file mode 100644 index 0000000..b04b18f Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/secondary-uk-37d1647a7d.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/secondary-usa-fa4e4594e1.jpg b/WonderQ-Admin-UI/public/assets/source/secondary-usa-fa4e4594e1.jpg new file mode 100644 index 0000000..ba012fc Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/secondary-usa-fa4e4594e1.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/secondary-xinjiang-7bdff060a5.jpg b/WonderQ-Admin-UI/public/assets/source/secondary-xinjiang-7bdff060a5.jpg new file mode 100644 index 0000000..487e564 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/secondary-xinjiang-7bdff060a5.jpg differ diff --git a/WonderQ-Admin-UI/public/assets/source/secondary-yunnan-cce4700549.png b/WonderQ-Admin-UI/public/assets/source/secondary-yunnan-cce4700549.png new file mode 100644 index 0000000..9c27c88 Binary files /dev/null and b/WonderQ-Admin-UI/public/assets/source/secondary-yunnan-cce4700549.png differ diff --git a/WonderQ-Admin-UI/src/App.tsx b/WonderQ-Admin-UI/src/App.tsx new file mode 100644 index 0000000..4731747 --- /dev/null +++ b/WonderQ-Admin-UI/src/App.tsx @@ -0,0 +1,20 @@ +import { useEffect, useState } from "react"; + +import { getToken } from "./api"; +import { AdminShell } from "@/components/admin/AdminShell"; +import { subscribeAuthExpired } from "@/lib/auth-session"; +import { LoginPage } from "@/pages/login/LoginPage"; + +export default function App() { + const [authed, setAuthed] = useState(!!getToken()); + + useEffect(() => { + return subscribeAuthExpired(() => setAuthed(false)); + }, []); + + if (!authed) { + return setAuthed(true)} />; + } + + return setAuthed(false)} />; +} diff --git a/WonderQ-Admin-UI/src/api.ts b/WonderQ-Admin-UI/src/api.ts new file mode 100644 index 0000000..2a30ee5 --- /dev/null +++ b/WonderQ-Admin-UI/src/api.ts @@ -0,0 +1,478 @@ +import { notifyAuthExpired, shouldExpireAdminSession } from "@/lib/auth-session"; + +export type Dashboard = { + stats: { + productCount: number; + publishedProductCount: number; + destinationCount: number; + newLeadCount: number; + leadCount: number; + campaignCount: number; + }; + recentLeads: Lead[]; +}; + +export type Destination = { + id: string; + name: string; + slug: string; + region?: string | null; + image?: string | null; + isHot: boolean; + isActive: boolean; + sortOrder: number; + aliases?: { id: string; alias: string }[]; + _count?: { products: number }; +}; + +export type DestinationHero = { + id: string; + title: string; + kicker: string | null; + image: string | null; + isActive: boolean; + sortOrder: number; + createdAt?: string; + updatedAt?: string; +}; + +export type DestinationRegion = { + id: string; + label: string; + keyword?: string | null; + spots?: string | null; + isActive: boolean; + sortOrder: number; + createdAt?: string; + updatedAt?: string; +}; + +export type DemandHero = { + id: string; + title: string; + kicker?: string | null; + description?: string | null; + steps: string[]; + isActive: boolean; + sortOrder: number; + createdAt?: string; + updatedAt?: string; +}; + +export type DemandFeatureCard = { + id: string; + title: string; + description?: string | null; + isActive: boolean; + sortOrder: number; + createdAt?: string; + updatedAt?: string; +}; + +export type DemandForm = { + id: string; + destinationLabel: string; + destinationPlaceholder?: string | null; + phoneLabel: string; + phonePlaceholder?: string | null; + noteLabel: string; + notePlaceholder?: string | null; + submitLabel: string; + chips: string[]; + isActive: boolean; + createdAt?: string; + updatedAt?: string; +}; + +export type DemandRecommendation = { + id: string; + title: string; + subtitle?: string | null; + productIds: string[]; + isActive: boolean; + sortOrder: number; + createdAt?: string; + updatedAt?: string; +}; + +export type Product = { + id: string; + sourceId?: number | null; + title: string; + subtitle?: string | null; + priceAmount?: number | null; + priceUnit: string; + tags: string[]; + coverImage?: string | null; + summary?: string | null; + images?: Array<{ id?: string; url: string; alt?: string | null; sortOrder: number }>; + detailSections?: ProductDetailSection[] | null; + status: "draft" | "published" | "archived"; + sortWeight: number; + updatedAt: string; + destination?: Destination | null; + destinationId?: string | null; +}; + +export type ProductDetailBlock = + | { type: "text"; text: string } + | { type: "image"; url: string; alt?: string | null }; + +export type ProductDetailSection = { + key: string; + label: string; + title?: string | null; + blocks: ProductDetailBlock[]; +}; + +export type LeadStatus = "new" | "assigned" | "contacted" | "planning" | "won" | "invalid"; + +export type Lead = { + id: string; + destination?: string | null; + phone: string; + travelDate?: string | null; + peopleCount?: number | null; + budgetMin?: number | null; + budgetMax?: number | null; + note?: string | null; + sourcePage?: string | null; + status: LeadStatus; + createdAt: string; + sourceProduct?: { id: string; title: string } | null; + assignedUser?: { id: string; name: string } | null; +}; + +export type LeadListParams = { + status?: LeadStatus; + sourcePage?: string; + keyword?: string; + createdFrom?: string; + createdTo?: string; + take?: number; +}; + +export type MediaAsset = { + id: string; + url: string; + name?: string | null; + mimeType?: string | null; + sizeBytes?: number | null; + group?: string | null; + createdAt?: string; + updatedAt?: string; +}; + +export type Campaign = { + id: string; + slug: string; + title: string; + description: string | null; + coverImage: string | null; + priceAmount: number | null; + priceUnit: string | null; + tags: string[]; + status: "draft" | "published"; + startsAt: string | null; + endsAt: string | null; + createdAt?: string; + updatedAt?: string; +}; + +export type RouteSection = { + id: string; + title: string; + subtitle?: string | null; + productIds: string[]; + isActive: boolean; + sortOrder: number; + createdAt?: string; + updatedAt?: string; +}; + +export type HotelGroup = { + id: string; + title: string; + description: string | null; + image: string | null; + coverImage?: string | null; + priceAmount?: number | null; + priceUnit?: string | null; + tags?: string[]; + status?: "draft" | "published"; + isActive: boolean; + sortOrder: number; + createdAt?: string; + updatedAt?: string; +}; + +export type VehicleOption = { + id: string; + title: string; + description: string | null; + image: string | null; + isActive: boolean; + sortOrder: number; + createdAt?: string; + updatedAt?: string; +}; + +export type SiteConfig = { + heroSlides: Array<{ id: string; title: string; kicker: string | null; image: string | null; isActive: boolean; sortOrder: number; createdAt?: string; updatedAt?: string }>; + destinations: Destination[]; + destinationHero: DestinationHero[]; + destinationRegions: DestinationRegion[]; + demandHero: DemandHero[]; + demandFeatureCards: DemandFeatureCard[]; + demandForm: DemandForm[]; + demandRecommendations: DemandRecommendation[]; + map: Array<{ id: string; image: string | null; isActive: boolean; createdAt?: string; updatedAt?: string }>; + themes: Array<{ id: string; label: string; image: string; targetType?: string | null; targetValue?: string | null; isActive: boolean }>; + campaigns: Campaign[]; + routeSections: RouteSection[]; + hotelGroups: HotelGroup[]; + vehicleOptions: VehicleOption[]; + ctaBanners: Array<{ id: string; alt: string; image: string; targetType: string; targetValue?: string | null; isActive: boolean; sortOrder: number; createdAt?: string; updatedAt?: string }>; +}; + +export type SiteModule = + | "heroSlides" + | "destinations" + | "destinationHero" + | "destinationRegions" + | "demandHero" + | "demandFeatureCards" + | "demandForm" + | "demandRecommendations" + | "map" + | "themes" + | "campaigns" + | "routeSections" + | "hotelGroups" + | "vehicleOptions" + | "ctaBanners"; +export type SiteConfigItem = SiteConfig[SiteModule][number]; +type SiteConfigItemResponse = SiteConfigItem | { item: SiteConfigItem }; + +export type SiteItemPatch = { + title?: string; + subtitle?: string | null; + kicker?: string | null; + name?: string; + slug?: string; + region?: string | null; + label?: string; + keyword?: string | null; + spots?: string | null; + alt?: string; + image?: string | null; + description?: string | null; + coverImage?: string | null; + priceAmount?: number | null; + priceUnit?: string | null; + tags?: string[]; + steps?: string[]; + destinationLabel?: string; + destinationPlaceholder?: string | null; + phoneLabel?: string; + phonePlaceholder?: string | null; + noteLabel?: string; + notePlaceholder?: string | null; + submitLabel?: string; + chips?: string[]; + targetType?: string | null; + targetValue?: string | null; + isHot?: boolean; + isActive?: boolean; + sortOrder?: number; + productIds?: string[]; + status?: "draft" | "published"; + startsAt?: string | null; + endsAt?: string | null; +}; + +export type ProductInput = { + title: string; + subtitle?: string; + destinationId?: string | null; + priceAmount?: number | null; + priceUnit?: string; + tags: string[]; + coverImage?: string | null; + summary?: string | null; + images?: Array<{ url: string; alt?: string | null; sortOrder: number }>; + detailSections?: ProductDetailSection[]; + status: "draft" | "published" | "archived"; + sortWeight: number; +}; + +const API_BASE = import.meta.env.VITE_API_BASE_URL ?? ""; +const TOKEN_KEY = "miniapp_admin_token"; + +export function getToken() { + return window.localStorage.getItem(TOKEN_KEY); +} + +export function setToken(token: string) { + window.localStorage.setItem(TOKEN_KEY, token); +} + +export function clearToken() { + window.localStorage.removeItem(TOKEN_KEY); +} + +function handleAuthExpired() { + clearToken(); + notifyAuthExpired(); +} + +async function request(path: string, options: RequestInit = {}): Promise { + const headers = new Headers(options.headers); + headers.set("Content-Type", "application/json"); + const token = getToken(); + if (token) headers.set("Authorization", `Bearer ${token}`); + + const response = await fetch(`${API_BASE}${path}`, { + ...options, + headers, + }); + + if (!response.ok) { + if (path !== "/api/admin/auth/login" && shouldExpireAdminSession(response.status, Boolean(token))) { + handleAuthExpired(); + } + const body = await response.json().catch(() => ({})); + throw new Error(body.message ?? `请求失败:${response.status}`); + } + + return response.json() as Promise; +} + +export async function login(email: string, password: string) { + return request<{ token: string; user: { name: string; email: string; role: string } }>("/api/admin/auth/login", { + method: "POST", + body: JSON.stringify({ email, password }), + }); +} + +export async function getDashboard() { + return request("/api/admin/dashboard"); +} + +export async function getProducts(keyword = "") { + const search = keyword ? `?keyword=${encodeURIComponent(keyword)}` : ""; + return request<{ items: Product[] }>(`/api/admin/products${search}`); +} + +export async function createProduct(input: ProductInput) { + return request("/api/admin/products", { + method: "POST", + body: JSON.stringify(input), + }); +} + +export async function updateProduct(id: string, input: Partial) { + return request(`/api/admin/products/${id}`, { + method: "PATCH", + body: JSON.stringify(input), + }); +} + +export async function getDestinations() { + return request<{ items: Destination[] }>("/api/admin/destinations"); +} + +export async function uploadMediaAsset(file: File, group = "site-config") { + const form = new FormData(); + form.set("file", file); + form.set("group", group); + const headers = new Headers(); + const token = getToken(); + if (token) headers.set("Authorization", `Bearer ${token}`); + + const response = await fetch(`${API_BASE}/api/admin/media-assets/upload`, { + method: "POST", + headers, + body: form, + }); + + if (!response.ok) { + if (shouldExpireAdminSession(response.status, Boolean(token))) { + handleAuthExpired(); + } + const body = await response.json().catch(() => ({})); + throw new Error(body.message ?? `请求失败:${response.status}`); + } + + return response.json() as Promise; +} + +export async function getSiteConfig() { + return request("/api/admin/site-config"); +} + +function unwrapSiteConfigItem(response: SiteConfigItemResponse) { + return "item" in response ? response.item : response; +} + +export async function createSiteConfigItem(module: SiteModule, input: SiteItemPatch) { + const response = await request(`/api/admin/site-config/${module}`, { + method: "POST", + body: JSON.stringify(input), + }); + return unwrapSiteConfigItem(response); +} + +export async function updateSiteConfigItem(module: SiteModule, id: string, input: SiteItemPatch) { + const response = await request(`/api/admin/site-config/${module}/${id}`, { + method: "PATCH", + body: JSON.stringify(input), + }); + return unwrapSiteConfigItem(response); +} + +export async function deleteSiteConfigItem(module: SiteModule, id: string) { + return request<{ id: string }>(`/api/admin/site-config/${module}/${id}`, { + method: "DELETE", + }); +} + +export async function reorderSiteConfigItems(module: SiteModule, itemIds: string[]) { + return request<{ items: SiteConfigItem[] }>(`/api/admin/site-config/${module}/reorder`, { + method: "PATCH", + body: JSON.stringify({ itemIds }), + }); +} + +export async function getLeads(params: LeadListParams = {}) { + const search = new URLSearchParams(); + if (params.status) search.set("status", params.status); + if (params.sourcePage) search.set("sourcePage", params.sourcePage); + if (params.keyword) search.set("keyword", params.keyword); + if (params.createdFrom) search.set("createdFrom", params.createdFrom); + if (params.createdTo) search.set("createdTo", params.createdTo); + if (params.take) search.set("take", String(params.take)); + const query = search.toString(); + return request<{ items: Lead[] }>(`/api/admin/leads${query ? `?${query}` : ""}`); +} + +export async function updateLeadStatus(id: string, status: Lead["status"]) { + return request(`/api/admin/leads/${id}/status`, { + method: "PATCH", + body: JSON.stringify({ status }), + }); +} + +export async function publishSite() { + return request<{ id: string; title: string; publishedAt: string }>("/api/admin/publish", { + method: "POST", + body: JSON.stringify({}), + }); +} + +export async function resetGuizhouContent() { + return request<{ heroSlides: number; destinations: number; themes: number; ctaBanners: number; routeSections?: number; products: number }>("/api/admin/reset-guizhou-content", { + method: "POST", + body: JSON.stringify({}), + }); +} diff --git a/WonderQ-Admin-UI/src/components/admin/AdminDisclosure.tsx b/WonderQ-Admin-UI/src/components/admin/AdminDisclosure.tsx new file mode 100644 index 0000000..777fff4 --- /dev/null +++ b/WonderQ-Admin-UI/src/components/admin/AdminDisclosure.tsx @@ -0,0 +1,23 @@ +import type { ReactNode } from "react"; + +export function AdminDisclosure({ + title, + description, + children, +}: { + title: string; + description?: string; + children: ReactNode; +}) { + return ( +
+
+ + {title} + {description ? {description} : null} + +
+
{children}
+
+ ); +} diff --git a/WonderQ-Admin-UI/src/components/admin/AdminShell.tsx b/WonderQ-Admin-UI/src/components/admin/AdminShell.tsx new file mode 100644 index 0000000..4f0f264 --- /dev/null +++ b/WonderQ-Admin-UI/src/components/admin/AdminShell.tsx @@ -0,0 +1,140 @@ +import { useEffect, useMemo, useState } from "react"; +import { Blocks, Home, LogOut, MapPin, Package, UserRoundCheck } from "lucide-react"; + +import { clearToken, getDestinations } from "@/api"; +import type { Destination } from "@/api"; +import { ToastStack } from "@/components/admin/ToastStack"; +import { Button } from "@/components/ui/button"; +import { LeadsPage } from "@/pages/leads/LeadsPage"; +import { ProductsPage } from "@/pages/products/ProductsPage"; +import { StructurePage } from "@/pages/structure/StructurePage"; +import type { Tab, Toast } from "@/types/admin"; + +const sidebarGroups: { id: string; label: string; items: { id: Tab; label: string; icon: typeof Home; description: string }[] }[] = [ + { + id: "workspace", + label: "工作台", + items: [{ id: "structure", label: "维护地图", icon: Blocks, description: "前台结构总览" }], + }, + { + id: "frontend", + label: "前台页面", + items: [ + { id: "home", label: "小程序首页", icon: Home, description: "轮播、主题、CTA" }, + { id: "destinations", label: "目的地页", icon: MapPin, description: "主视觉、热门、省内" }, + { id: "products", label: "商品维护", icon: Package, description: "列表、卡片、详情" }, + ], + }, + { + id: "operations", + label: "业务处理", + items: [{ id: "leads", label: "需求线索", icon: UserRoundCheck, description: "表单和跟进" }], + }, +]; + +const tabs = sidebarGroups.flatMap((group) => group.items); +const hiddenTabs: Partial> = { + leadList: { label: "线索查询跟进", description: "表单查询和状态流转" }, +}; + +export function AdminShell({ onLogout }: { onLogout: () => void }) { + const [activeTab, setActiveTab] = useState("structure"); + const [destinations, setDestinations] = useState([]); + const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false); + const [toasts, setToasts] = useState([]); + + useEffect(() => { + getDestinations() + .then((result) => setDestinations(result.items)) + .catch(() => setDestinations([])); + }, [activeTab]); + + useEffect(() => { + setHasUnsavedChanges(false); + }, [activeTab]); + + const activeMeta = useMemo(() => tabs.find((tab) => tab.id === activeTab) ?? hiddenTabs[activeTab], [activeTab]); + const activeLabel = activeMeta?.label ?? ""; + const activeDescription = activeMeta?.description ?? ""; + + const notify = (toast: Omit) => { + const id = `toast-${Date.now()}-${Math.random().toString(16).slice(2)}`; + setToasts((items) => [...items, { ...toast, id }]); + window.setTimeout(() => { + setToasts((items) => items.filter((item) => item.id !== id)); + }, 4200); + }; + + const logout = () => { + clearToken(); + onLogout(); + }; + + return ( +
+ +
+
+
+ {activeLabel} + {activeDescription} · 结构化维护 · 内存开发模式 +
+
+ + {hasUnsavedChanges ? "有未提交修改" : "内容已同步"} + +
+
+ {activeTab === "structure" ? ( + + ) : activeTab === "home" ? ( + + ) : activeTab === "destinations" ? ( + + ) : activeTab === "products" ? ( + + ) : activeTab === "leads" ? ( + + ) : ( + + )} +
+ setToasts((items) => items.filter((item) => item.id !== id))} /> +
+ ); +} diff --git a/WonderQ-Admin-UI/src/components/admin/EmptyState.tsx b/WonderQ-Admin-UI/src/components/admin/EmptyState.tsx new file mode 100644 index 0000000..ca76619 --- /dev/null +++ b/WonderQ-Admin-UI/src/components/admin/EmptyState.tsx @@ -0,0 +1,3 @@ +export function EmptyState({ text }: { text: string }) { + return
{text}
; +} diff --git a/WonderQ-Admin-UI/src/components/admin/SingleImageUploader.tsx b/WonderQ-Admin-UI/src/components/admin/SingleImageUploader.tsx new file mode 100644 index 0000000..325af75 --- /dev/null +++ b/WonderQ-Admin-UI/src/components/admin/SingleImageUploader.tsx @@ -0,0 +1,102 @@ +import { ChangeEvent, useRef, useState } from "react"; +import { Image as ImageIcon, Trash2 } from "lucide-react"; + +import { uploadMediaAsset } from "@/api"; + +const MAX_IMAGE_BYTES = 5 * 1024 * 1024; +const ALLOWED_IMAGE_TYPES = new Set(["image/jpeg", "image/png", "image/webp", "image/gif"]); + +export function SingleImageUploader({ + value, + onChange, + group = "site-config", +}: { + value?: string | null; + onChange: (value: string | null) => void; + group?: string; +}) { + const inputRef = useRef(null); + const [error, setError] = useState(""); + const [uploading, setUploading] = useState(false); + const openFilePicker = () => inputRef.current?.click(); + const displayValue = value ?? ""; + const hasImage = Boolean(displayValue); + + const handleFileChange = async (event: ChangeEvent) => { + const file = event.target.files?.[0]; + event.target.value = ""; + if (!file) return; + + if (!ALLOWED_IMAGE_TYPES.has(file.type)) { + setError("请选择 JPG、PNG、WebP 或 GIF 图片。"); + return; + } + if (file.size > MAX_IMAGE_BYTES) { + setError("图片大小不能超过 5MB。"); + return; + } + + try { + setUploading(true); + const asset = await uploadMediaAsset(file, group); + setError(""); + onChange(asset.url); + } catch (err) { + setError(err instanceof Error ? err.message : "图片上传失败,请重新选择。"); + } finally { + setUploading(false); + } + }; + + const handleRemove = () => { + onChange(null); + }; + + return ( +
+ +
+ + {hasImage ? ( +
+ +
+ ) : null} +
+ {error ?

{error}

: null} +
+ ); +} diff --git a/WonderQ-Admin-UI/src/components/admin/ToastStack.tsx b/WonderQ-Admin-UI/src/components/admin/ToastStack.tsx new file mode 100644 index 0000000..ea7b7bf --- /dev/null +++ b/WonderQ-Admin-UI/src/components/admin/ToastStack.tsx @@ -0,0 +1,25 @@ +import { AlertTriangle, CheckCircle2, X } from "lucide-react"; + +import { Button } from "@/components/ui/button"; +import type { Toast } from "@/types/admin"; + +export function ToastStack({ toasts, onClose }: { toasts: Toast[]; onClose: (id: string) => void }) { + if (!toasts.length) return null; + + return ( +
+ {toasts.map((toast) => ( +
+ {toast.tone === "success" ? : } + + {toast.title} + {toast.message} + + +
+ ))} +
+ ); +} diff --git a/WonderQ-Admin-UI/src/components/admin/route-sections/RouteProductQuickCreateForm.tsx b/WonderQ-Admin-UI/src/components/admin/route-sections/RouteProductQuickCreateForm.tsx new file mode 100644 index 0000000..6b2c624 --- /dev/null +++ b/WonderQ-Admin-UI/src/components/admin/route-sections/RouteProductQuickCreateForm.tsx @@ -0,0 +1,251 @@ +import { Plus, X } from "lucide-react"; +import { MutableRefObject, useEffect, useState } from "react"; + +import type { Product, ProductInput } from "@/api"; +import { AdminDisclosure } from "@/components/admin/AdminDisclosure"; +import { SingleImageUploader } from "@/components/admin/SingleImageUploader"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Switch } from "@/components/ui/switch"; +import { Textarea } from "@/components/ui/textarea"; + +type QuickRouteDraft = { + title: string; + summary: string; + destinationName: string; + priceAmount: number | null; + priceUnit: string; + tags: string[]; + coverImage: string; + published: boolean; + sortWeight: number; +}; + +function createEmptyDraft(): QuickRouteDraft { + return { + title: "", + summary: "", + destinationName: "", + priceAmount: null, + priceUnit: "起/人", + tags: ["", ""], + coverImage: "", + published: true, + sortWeight: 0, + }; +} + +function createDraftFromProduct(product?: Product | null): QuickRouteDraft { + if (!product) return createEmptyDraft(); + + const tags = product.tags.length ? product.tags.slice(0, 3) : ["", ""]; + + return { + title: product.title, + summary: product.summary ?? "", + destinationName: product.subtitle ?? product.destination?.name ?? "", + priceAmount: product.priceAmount ?? null, + priceUnit: product.priceUnit || "起/人", + tags: tags.length === 1 ? [...tags, ""] : tags, + coverImage: product.coverImage ?? "", + published: product.status === "published", + sortWeight: product.sortWeight ?? 0, + }; +} + +export function RouteProductQuickCreateForm({ + product, + onCreate, + onUpdate, + onSubmitRef, +}: { + product?: Product | null; + onCreate: (input: ProductInput) => Promise; + onUpdate: (productId: string, input: ProductInput) => Promise; + onSubmitRef: MutableRefObject<(() => Promise) | null>; +}) { + const [draft, setDraft] = useState(() => createDraftFromProduct(product)); + const editing = Boolean(product); + + const submit = async () => { + const title = draft.title.trim(); + if (!title) return; + + const input: ProductInput = { + title, + subtitle: draft.destinationName.trim(), + destinationId: null, + priceAmount: draft.priceAmount, + priceUnit: draft.priceUnit.trim() || "起/人", + tags: draft.tags.map((tag) => tag.trim()).filter(Boolean).slice(0, 3), + coverImage: draft.coverImage.trim() || null, + summary: draft.summary.trim(), + images: product?.images ?? [], + detailSections: product?.detailSections ?? [], + status: draft.published ? "published" : "draft", + sortWeight: draft.sortWeight, + }; + + if (editing && product) { + await onUpdate(product.id, input); + return; + } + + await onCreate(input); + setDraft(createEmptyDraft()); + }; + + useEffect(() => { + setDraft(createDraftFromProduct(product)); + }, [product?.id, product?.updatedAt]); + + useEffect(() => { + onSubmitRef.current = submit; + return () => { + onSubmitRef.current = null; + }; + }, [draft, product?.id, product?.updatedAt, onSubmitRef]); + + return ( +
+ + +