diff --git a/Cunkebao/.gitignore b/Cunkebao/.gitignore
new file mode 100644
index 00000000..b512c09d
--- /dev/null
+++ b/Cunkebao/.gitignore
@@ -0,0 +1 @@
+node_modules
\ No newline at end of file
diff --git a/Cunkebao/App.vue b/Cunkebao/App.vue
new file mode 100644
index 00000000..b0333295
--- /dev/null
+++ b/Cunkebao/App.vue
@@ -0,0 +1,69 @@
+
+
+
\ No newline at end of file
diff --git a/Cunkebao/README.md b/Cunkebao/README.md
new file mode 100644
index 00000000..1d881a83
--- /dev/null
+++ b/Cunkebao/README.md
@@ -0,0 +1,86 @@
+# 村客宝 UniApp
+
+基于uni-app框架开发的村客宝移动端应用,支持H5、微信小程序、App等多端部署。
+
+## 项目结构
+
+```
+├── api # API接口目录
+├── components # 自定义组件
+├── pages # 页面文件目录
+│ ├── index # 首页
+│ ├── login # 登录页面
+│ └── agreement # 协议页面
+├── static # 静态资源
+│ ├── images # 图片
+│ └── icons # 图标
+├── store # Vuex状态管理
+├── utils # 工具函数
+│ ├── auth.js # 认证相关工具函数
+│ ├── common.js # 通用工具函数
+│ └── request.js # 请求工具函数
+├── App.vue # 应用配置,用来配置App全局样式以及监听应用生命周期
+├── main.js # Vue初始化入口文件
+├── manifest.json # 配置应用名称、appid、logo、版本等打包信息
+├── pages.json # 配置页面路由、导航条、选项卡等页面类信息
+└── uni.scss # 全局样式变量
+```
+
+## 功能特性
+
+- **支持多种登录方式**:手机号验证码登录、密码登录、微信授权登录、Apple登录
+- **完整的token认证机制**:JWT令牌管理,自动刷新token,过期处理
+- **统一的网络请求封装**:请求拦截器,响应拦截器,错误处理
+- **多端适配**:一套代码,同时支持H5、微信小程序、App
+- **UI框架集成**:基于uView 2.x UI框架,提供丰富的组件和样式
+- **主题定制**:全局样式变量,支持自定义主题
+
+## 开发环境
+
+- **Node.js**: v14.x及以上
+- **HBuilderX**: 3.x及以上版本
+
+### 安装依赖
+
+1. 使用HBuilderX打开项目
+2. 点击菜单栏 "工具 -> 插件安装",安装"scss/sass编译"插件
+3. 点击菜单栏 "工具 -> 插件安装",安装"uView-UI"插件
+
+## 运行和发布
+
+### 运行到浏览器
+
+1. 在HBuilderX中,点击"运行 -> 运行到浏览器"
+2. 选择浏览器,如Chrome
+
+### 运行到微信小程序
+
+1. 在HBuilderX中,点击"运行 -> 运行到小程序模拟器 -> 微信开发者工具"
+2. 确保已安装并配置了微信开发者工具
+
+### 发布为H5
+
+1. 在HBuilderX中,点击"发行 -> 网站H5发布"
+2. 配置发布信息,点击发布
+
+### 发布为微信小程序
+
+1. 在HBuilderX中,点击"发行 -> 小程序发布 -> 微信小程序"
+2. 配置小程序AppID等信息,点击发布
+
+### 发布为App
+
+1. 在HBuilderX中,点击"发行 -> 原生App-云打包"
+2. 配置证书等信息,选择打包平台(Android/iOS),点击发布
+
+## 技术栈
+
+- **uni-app**:跨平台前端框架
+- **Vue.js**:前端框架
+- **Vuex**:状态管理
+- **uView UI**:UI组件库
+- **SCSS**:CSS预处理器
+
+## License
+
+MIT
\ No newline at end of file
diff --git a/Cunkebao/api/user.js b/Cunkebao/api/user.js
new file mode 100644
index 00000000..ae7c147b
--- /dev/null
+++ b/Cunkebao/api/user.js
@@ -0,0 +1,107 @@
+import request from '@/utils/request'
+
+/**
+ * 用户登录
+ * @param {Object} data 登录数据
+ * @param {string} data.username 用户名
+ * @param {string} data.password 密码
+ * @param {boolean} data.is_encrypted 密码是否已加密
+ * @returns {Promise} 登录结果
+ */
+export function login(data) {
+ return request({
+ url: '/api/auth/login',
+ method: 'POST',
+ data
+ })
+}
+
+/**
+ * 手机号验证码登录
+ * @param {Object} data 登录数据
+ * @param {string} data.mobile 手机号
+ * @param {string} data.code 验证码
+ * @returns {Promise} 登录结果
+ */
+export function mobileLogin(data) {
+ return request({
+ url: '/api/auth/mobile-login',
+ method: 'POST',
+ data
+ })
+}
+
+/**
+ * 发送验证码
+ * @param {Object} data 数据
+ * @param {string} data.mobile 手机号
+ * @param {string} data.type 验证码类型(login:登录,register:注册)
+ * @returns {Promise} 发送结果
+ */
+export function sendCode(data) {
+ return request({
+ url: '/api/auth/code',
+ method: 'POST',
+ data
+ })
+}
+
+/**
+ * 获取用户信息
+ * @returns {Promise} 用户信息
+ */
+export function getUserInfo() {
+ return request({
+ url: '/api/auth/info',
+ method: 'GET'
+ })
+}
+
+/**
+ * 刷新token
+ * @returns {Promise} 刷新结果
+ */
+export function refreshToken() {
+ return request({
+ url: '/api/auth/refresh',
+ method: 'POST'
+ })
+}
+
+/**
+ * 退出登录
+ * @returns {Promise} 退出结果
+ */
+export function logout() {
+ return new Promise(resolve => {
+ resolve({ code: 200, msg: '退出成功' })
+ })
+}
+
+/**
+ * 微信登录
+ * @param {Object} data 登录数据
+ * @param {string} data.code 微信授权码
+ * @returns {Promise} 登录结果
+ */
+export function wechatLogin(data) {
+ return request({
+ url: '/api/auth/wechat-login',
+ method: 'POST',
+ data
+ })
+}
+
+/**
+ * Apple登录
+ * @param {Object} data 登录数据
+ * @param {string} data.identityToken Apple身份令牌
+ * @returns {Promise} 登录结果
+ */
+export function appleLogin(data) {
+ return request({
+ url: '/api/auth/apple-login',
+ method: 'POST',
+ data
+ })
+}
\ No newline at end of file
diff --git a/Cunkebao/components/CustomTabBar.vue b/Cunkebao/components/CustomTabBar.vue
new file mode 100644
index 00000000..02ff322d
--- /dev/null
+++ b/Cunkebao/components/CustomTabBar.vue
@@ -0,0 +1,94 @@
+
+
+
+
+ 首页
+
+
+
+
+ 场景获客
+
+
+
+
+ 工作台
+
+
+
+
+ 我的
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Cunkebao/components/LineChart.vue b/Cunkebao/components/LineChart.vue
new file mode 100644
index 00000000..af7a2789
--- /dev/null
+++ b/Cunkebao/components/LineChart.vue
@@ -0,0 +1,253 @@
+
+
+
+
+
+ {{ value }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ label }}
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Cunkebao/components/TabBar.vue b/Cunkebao/components/TabBar.vue
new file mode 100644
index 00000000..d17718de
--- /dev/null
+++ b/Cunkebao/components/TabBar.vue
@@ -0,0 +1,96 @@
+
+
+
+
+ 首页
+
+
+
+
+ 场景获客
+
+
+
+
+ 工作台
+
+
+
+
+ 我的
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Cunkebao/main.js b/Cunkebao/main.js
new file mode 100644
index 00000000..0be225d2
--- /dev/null
+++ b/Cunkebao/main.js
@@ -0,0 +1,49 @@
+import Vue from 'vue'
+import App from './App'
+
+// 引入uView UI
+import uView from 'uview-ui'
+Vue.use(uView)
+
+// 设置为 false 以阻止 Vue 在启动时生成生产提示
+Vue.config.productionTip = false
+
+// 导入全局样式
+import './uni.scss'
+
+// 导入请求拦截和封装
+import Request from './utils/request'
+Vue.prototype.$request = Request
+
+// 导入API
+import * as UserApi from './api/user'
+Vue.prototype.$userApi = UserApi
+
+// 导入工具函数
+import Utils from './utils/common'
+Vue.prototype.$utils = Utils
+
+// 导入权限检查
+import Auth from './utils/auth'
+Vue.prototype.$auth = Auth
+
+App.mpType = 'app'
+
+// #ifdef MP
+// 引入uView对小程序分享的mixin封装
+const mpShare = require('uview-ui/libs/mixin/mpShare.js')
+Vue.mixin(mpShare)
+// #endif
+
+const app = new Vue({
+ ...App
+})
+
+// 挂载uView到Vue原型,使用时可以使用this.$u访问
+Vue.prototype.$u = Vue.prototype.$u || {}
+
+// 如果采用了自定义主题,必须加入这个
+import uviewTheme from './uni.scss'
+Vue.prototype.$u.config.unit = 'rpx'
+
+app.$mount()
\ No newline at end of file
diff --git a/Cunkebao/manifest.json b/Cunkebao/manifest.json
new file mode 100644
index 00000000..4743c167
--- /dev/null
+++ b/Cunkebao/manifest.json
@@ -0,0 +1,74 @@
+{
+ "name" : "村客宝",
+ "appid" : "",
+ "description" : "村客宝应用",
+ "versionName" : "1.0.0",
+ "versionCode" : "100",
+ "transformPx" : false,
+ "app-plus" : {
+ "usingComponents" : true,
+ "nvueStyleCompiler" : "uni-app",
+ "compilerVersion" : 3,
+ "splashscreen" : {
+ "alwaysShowBeforeRender" : true,
+ "waiting" : true,
+ "autoclose" : true,
+ "delay" : 0
+ },
+ "modules" : {},
+ "distribute" : {
+ "android" : {
+ "permissions" : [
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ ""
+ ]
+ },
+ "ios" : {
+ "dSYMs" : false
+ },
+ "sdkConfigs" : {
+ "ad" : {}
+ }
+ }
+ },
+ "quickapp" : {},
+ "mp-weixin" : {
+ "appid" : "",
+ "setting" : {
+ "urlCheck" : false
+ },
+ "usingComponents" : true
+ },
+ "mp-alipay" : {
+ "usingComponents" : true
+ },
+ "mp-baidu" : {
+ "usingComponents" : true
+ },
+ "mp-toutiao" : {
+ "usingComponents" : true
+ },
+ "h5" : {
+ "router" : {
+ "base" : "/"
+ },
+ "template" : "index.html",
+ "optimization" : {
+ "treeShaking" : {
+ "enable" : true
+ }
+ },
+ "title" : "村客宝"
+ }
+}
\ No newline at end of file
diff --git a/Cunkebao/package-lock.json b/Cunkebao/package-lock.json
new file mode 100644
index 00000000..8ec954d5
--- /dev/null
+++ b/Cunkebao/package-lock.json
@@ -0,0 +1,1762 @@
+{
+ "name": "cunkebao",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "cunkebao",
+ "version": "1.0.0",
+ "license": "ISC",
+ "dependencies": {
+ "uview-ui": "^2.0.31"
+ },
+ "devDependencies": {
+ "autoprefixer": "^10.4.21",
+ "postcss-comment": "^2.0.0",
+ "postcss-import": "^16.1.0",
+ "sass": "^1.32.13",
+ "sass-loader": "^10.1.1"
+ }
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.8",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
+ "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "@jridgewell/set-array": "^1.2.1",
+ "@jridgewell/sourcemap-codec": "^1.4.10",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/set-array": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
+ "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/source-map": {
+ "version": "0.3.6",
+ "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz",
+ "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.25"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
+ "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.25",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
+ "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@types/eslint": {
+ "version": "9.6.1",
+ "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz",
+ "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "@types/estree": "*",
+ "@types/json-schema": "*"
+ }
+ },
+ "node_modules/@types/eslint-scope": {
+ "version": "3.7.7",
+ "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz",
+ "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "@types/eslint": "*",
+ "@types/estree": "*"
+ }
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
+ "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/@types/json-schema": {
+ "version": "7.0.15",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
+ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+ "dev": true
+ },
+ "node_modules/@types/node": {
+ "version": "22.13.10",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.10.tgz",
+ "integrity": "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "undici-types": "~6.20.0"
+ }
+ },
+ "node_modules/@webassemblyjs/ast": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz",
+ "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "@webassemblyjs/helper-numbers": "1.13.2",
+ "@webassemblyjs/helper-wasm-bytecode": "1.13.2"
+ }
+ },
+ "node_modules/@webassemblyjs/floating-point-hex-parser": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz",
+ "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/@webassemblyjs/helper-api-error": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz",
+ "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/@webassemblyjs/helper-buffer": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz",
+ "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/@webassemblyjs/helper-numbers": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz",
+ "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "@webassemblyjs/floating-point-hex-parser": "1.13.2",
+ "@webassemblyjs/helper-api-error": "1.13.2",
+ "@xtuc/long": "4.2.2"
+ }
+ },
+ "node_modules/@webassemblyjs/helper-wasm-bytecode": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz",
+ "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/@webassemblyjs/helper-wasm-section": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz",
+ "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "@webassemblyjs/ast": "1.14.1",
+ "@webassemblyjs/helper-buffer": "1.14.1",
+ "@webassemblyjs/helper-wasm-bytecode": "1.13.2",
+ "@webassemblyjs/wasm-gen": "1.14.1"
+ }
+ },
+ "node_modules/@webassemblyjs/ieee754": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz",
+ "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "@xtuc/ieee754": "^1.2.0"
+ }
+ },
+ "node_modules/@webassemblyjs/leb128": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz",
+ "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "@xtuc/long": "4.2.2"
+ }
+ },
+ "node_modules/@webassemblyjs/utf8": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz",
+ "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/@webassemblyjs/wasm-edit": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz",
+ "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "@webassemblyjs/ast": "1.14.1",
+ "@webassemblyjs/helper-buffer": "1.14.1",
+ "@webassemblyjs/helper-wasm-bytecode": "1.13.2",
+ "@webassemblyjs/helper-wasm-section": "1.14.1",
+ "@webassemblyjs/wasm-gen": "1.14.1",
+ "@webassemblyjs/wasm-opt": "1.14.1",
+ "@webassemblyjs/wasm-parser": "1.14.1",
+ "@webassemblyjs/wast-printer": "1.14.1"
+ }
+ },
+ "node_modules/@webassemblyjs/wasm-gen": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz",
+ "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "@webassemblyjs/ast": "1.14.1",
+ "@webassemblyjs/helper-wasm-bytecode": "1.13.2",
+ "@webassemblyjs/ieee754": "1.13.2",
+ "@webassemblyjs/leb128": "1.13.2",
+ "@webassemblyjs/utf8": "1.13.2"
+ }
+ },
+ "node_modules/@webassemblyjs/wasm-opt": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz",
+ "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "@webassemblyjs/ast": "1.14.1",
+ "@webassemblyjs/helper-buffer": "1.14.1",
+ "@webassemblyjs/wasm-gen": "1.14.1",
+ "@webassemblyjs/wasm-parser": "1.14.1"
+ }
+ },
+ "node_modules/@webassemblyjs/wasm-parser": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz",
+ "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "@webassemblyjs/ast": "1.14.1",
+ "@webassemblyjs/helper-api-error": "1.13.2",
+ "@webassemblyjs/helper-wasm-bytecode": "1.13.2",
+ "@webassemblyjs/ieee754": "1.13.2",
+ "@webassemblyjs/leb128": "1.13.2",
+ "@webassemblyjs/utf8": "1.13.2"
+ }
+ },
+ "node_modules/@webassemblyjs/wast-printer": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz",
+ "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "@webassemblyjs/ast": "1.14.1",
+ "@xtuc/long": "4.2.2"
+ }
+ },
+ "node_modules/@xtuc/ieee754": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
+ "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/@xtuc/long": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
+ "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/acorn": {
+ "version": "8.14.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
+ "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
+ "dev": true,
+ "peer": true,
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/ajv-formats": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
+ "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "ajv": "^8.0.0"
+ },
+ "peerDependencies": {
+ "ajv": "^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "ajv": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/ajv-formats/node_modules/ajv": {
+ "version": "8.17.1",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
+ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3",
+ "fast-uri": "^3.0.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/ajv-formats/node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/ajv-keywords": {
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
+ "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
+ "dev": true,
+ "peerDependencies": {
+ "ajv": "^6.9.1"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dev": true,
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/autoprefixer": {
+ "version": "10.4.21",
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz",
+ "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/autoprefixer"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "browserslist": "^4.24.4",
+ "caniuse-lite": "^1.0.30001702",
+ "fraction.js": "^4.3.7",
+ "normalize-range": "^0.1.2",
+ "picocolors": "^1.1.1",
+ "postcss-value-parser": "^4.2.0"
+ },
+ "bin": {
+ "autoprefixer": "bin/autoprefixer"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ },
+ "peerDependencies": {
+ "postcss": "^8.1.0"
+ }
+ },
+ "node_modules/big.js": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
+ "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+ "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "dev": true,
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/browserslist": {
+ "version": "4.24.4",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz",
+ "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "caniuse-lite": "^1.0.30001688",
+ "electron-to-chromium": "^1.5.73",
+ "node-releases": "^2.0.19",
+ "update-browserslist-db": "^1.1.1"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/buffer-from": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001706",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001706.tgz",
+ "integrity": "sha512-3ZczoTApMAZwPKYWmwVbQMFpXBDds3/0VciVoUwPUbldlYyVLmRVuRs/PcUZtHpbLRpzzDvrvnFuREsGt6lUug==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ]
+ },
+ "node_modules/chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/chalk/node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/chalk/node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+ "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+ "dev": true,
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/chrome-trace-event": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz",
+ "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">=6.0"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+ "dev": true
+ },
+ "node_modules/commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.123",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.123.tgz",
+ "integrity": "sha512-refir3NlutEZqlKaBLK0tzlVLe5P2wDKS7UQt/3SpibizgsRAPOsqQC3ffw1nlv3ze5gjRQZYHoPymgVZkplFA==",
+ "dev": true
+ },
+ "node_modules/emojis-list": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
+ "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/enhanced-resolve": {
+ "version": "5.18.1",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz",
+ "integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "graceful-fs": "^4.2.4",
+ "tapable": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/es-module-lexer": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz",
+ "integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/eslint-scope": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
+ "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^4.1.1"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esrecurse/node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estraverse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/events": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">=0.8.x"
+ }
+ },
+ "node_modules/fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "dev": true
+ },
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true
+ },
+ "node_modules/fast-uri": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz",
+ "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fastify"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/fastify"
+ }
+ ],
+ "peer": true
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "dev": true,
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/fraction.js": {
+ "version": "4.3.7",
+ "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
+ "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "type": "patreon",
+ "url": "https://github.com/sponsors/rawify"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/glob-to-regexp": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
+ "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "dev": true,
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-core-module": {
+ "version": "2.16.1",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
+ "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
+ "dev": true,
+ "dependencies": {
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/jest-worker": {
+ "version": "27.5.1",
+ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
+ "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "@types/node": "*",
+ "merge-stream": "^2.0.0",
+ "supports-color": "^8.0.0"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ }
+ },
+ "node_modules/json-parse-even-better-errors": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ },
+ "node_modules/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "dev": true,
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/klona": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz",
+ "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/loader-runner": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz",
+ "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">=6.11.5"
+ }
+ },
+ "node_modules/loader-utils": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
+ "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
+ "dev": true,
+ "dependencies": {
+ "big.js": "^5.2.2",
+ "emojis-list": "^3.0.0",
+ "json5": "^2.1.2"
+ },
+ "engines": {
+ "node": ">=8.9.0"
+ }
+ },
+ "node_modules/merge-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.11",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
+ "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "peer": true,
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/neo-async": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
+ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
+ "dev": true
+ },
+ "node_modules/node-releases": {
+ "version": "2.0.19",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
+ "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
+ "dev": true
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/normalize-range": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
+ "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+ "dev": true
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "dev": true
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.5.3",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
+ "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "peer": true,
+ "dependencies": {
+ "nanoid": "^3.3.8",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/postcss-comment": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/postcss-comment/-/postcss-comment-2.0.0.tgz",
+ "integrity": "sha512-5zT5iKU7c0tK9KJFNrVf+g1MGTkzf/4V3e0Zzm2g1uoFQC5jeTHmB9O1iAqh97+jnKpc6al204e0pwFUiCwseg==",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^6.0.0"
+ }
+ },
+ "node_modules/postcss-comment/node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/postcss-comment/node_modules/postcss": {
+ "version": "6.0.23",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
+ "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^2.4.1",
+ "source-map": "^0.6.1",
+ "supports-color": "^5.4.0"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/postcss-comment/node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/postcss-import": {
+ "version": "16.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-16.1.0.tgz",
+ "integrity": "sha512-7hsAZ4xGXl4MW+OKEWCnF6T5jqBw80/EE9aXg1r2yyn1RsVEU8EtKXbijEODa+rg7iih4bKf7vlvTGYR4CnPNg==",
+ "dev": true,
+ "dependencies": {
+ "postcss-value-parser": "^4.0.0",
+ "read-cache": "^1.0.0",
+ "resolve": "^1.1.7"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.0.0"
+ }
+ },
+ "node_modules/postcss-value-parser": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
+ "dev": true
+ },
+ "node_modules/punycode": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/randombytes": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+ "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "safe-buffer": "^5.1.0"
+ }
+ },
+ "node_modules/read-cache": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
+ "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
+ "dev": true,
+ "dependencies": {
+ "pify": "^2.3.0"
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dev": true,
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/require-from-string": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/resolve": {
+ "version": "1.22.10",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
+ "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
+ "dev": true,
+ "dependencies": {
+ "is-core-module": "^2.16.0",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "peer": true
+ },
+ "node_modules/sass": {
+ "version": "1.32.13",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.32.13.tgz",
+ "integrity": "sha512-dEgI9nShraqP7cXQH+lEXVf73WOPCse0QlFzSD8k+1TcOxCMwVXfQlr0jtoluZysQOyJGnfr21dLvYKDJq8HkA==",
+ "dev": true,
+ "dependencies": {
+ "chokidar": ">=3.0.0 <4.0.0"
+ },
+ "bin": {
+ "sass": "sass.js"
+ },
+ "engines": {
+ "node": ">=8.9.0"
+ }
+ },
+ "node_modules/sass-loader": {
+ "version": "10.1.1",
+ "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-10.1.1.tgz",
+ "integrity": "sha512-W6gVDXAd5hR/WHsPicvZdjAWHBcEJ44UahgxcIE196fW2ong0ZHMPO1kZuI5q0VlvMQZh32gpv69PLWQm70qrw==",
+ "dev": true,
+ "dependencies": {
+ "klona": "^2.0.4",
+ "loader-utils": "^2.0.0",
+ "neo-async": "^2.6.2",
+ "schema-utils": "^3.0.0",
+ "semver": "^7.3.2"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ },
+ "peerDependencies": {
+ "fibers": ">= 3.1.0",
+ "node-sass": "^4.0.0 || ^5.0.0",
+ "sass": "^1.3.0",
+ "webpack": "^4.36.0 || ^5.0.0"
+ },
+ "peerDependenciesMeta": {
+ "fibers": {
+ "optional": true
+ },
+ "node-sass": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/schema-utils": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
+ "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
+ "dev": true,
+ "dependencies": {
+ "@types/json-schema": "^7.0.8",
+ "ajv": "^6.12.5",
+ "ajv-keywords": "^3.5.2"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ }
+ },
+ "node_modules/semver": {
+ "version": "7.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
+ "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/serialize-javascript": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
+ "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "randombytes": "^2.1.0"
+ }
+ },
+ "node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/source-map-support": {
+ "version": "0.5.21",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+ "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "buffer-from": "^1.0.0",
+ "source-map": "^0.6.0"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/supports-color?sponsor=1"
+ }
+ },
+ "node_modules/supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/tapable": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
+ "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/terser": {
+ "version": "5.39.0",
+ "resolved": "https://registry.npmjs.org/terser/-/terser-5.39.0.tgz",
+ "integrity": "sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "@jridgewell/source-map": "^0.3.3",
+ "acorn": "^8.8.2",
+ "commander": "^2.20.0",
+ "source-map-support": "~0.5.20"
+ },
+ "bin": {
+ "terser": "bin/terser"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/terser-webpack-plugin": {
+ "version": "5.3.14",
+ "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz",
+ "integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "@jridgewell/trace-mapping": "^0.3.25",
+ "jest-worker": "^27.4.5",
+ "schema-utils": "^4.3.0",
+ "serialize-javascript": "^6.0.2",
+ "terser": "^5.31.1"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ },
+ "peerDependencies": {
+ "webpack": "^5.1.0"
+ },
+ "peerDependenciesMeta": {
+ "@swc/core": {
+ "optional": true
+ },
+ "esbuild": {
+ "optional": true
+ },
+ "uglify-js": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/terser-webpack-plugin/node_modules/ajv": {
+ "version": "8.17.1",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
+ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3",
+ "fast-uri": "^3.0.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
+ "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3"
+ },
+ "peerDependencies": {
+ "ajv": "^8.8.2"
+ }
+ },
+ "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/terser-webpack-plugin/node_modules/schema-utils": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz",
+ "integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "@types/json-schema": "^7.0.9",
+ "ajv": "^8.9.0",
+ "ajv-formats": "^2.1.1",
+ "ajv-keywords": "^5.1.0"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "6.20.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
+ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/update-browserslist-db": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
+ "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "escalade": "^3.2.0",
+ "picocolors": "^1.1.1"
+ },
+ "bin": {
+ "update-browserslist-db": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
+ "node_modules/uri-js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "dev": true,
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/uview-ui": {
+ "version": "2.0.31",
+ "resolved": "https://registry.npmjs.org/uview-ui/-/uview-ui-2.0.31.tgz",
+ "integrity": "sha512-I/0fGuvtiKHH/mBb864SGYk+SJ7WaF32tsBgYgeBOsxlUp+Th+Ac2tgz2cTvsQJl6eZYWsKZ3ixiSXCAcxZ8Sw==",
+ "engines": {
+ "HBuilderX": "^3.1.0"
+ }
+ },
+ "node_modules/watchpack": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz",
+ "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "glob-to-regexp": "^0.4.1",
+ "graceful-fs": "^4.1.2"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/webpack": {
+ "version": "5.98.0",
+ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.98.0.tgz",
+ "integrity": "sha512-UFynvx+gM44Gv9qFgj0acCQK2VE1CtdfwFdimkapco3hlPCJ/zeq73n2yVKimVbtm+TnApIugGhLJnkU6gjYXA==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "@types/eslint-scope": "^3.7.7",
+ "@types/estree": "^1.0.6",
+ "@webassemblyjs/ast": "^1.14.1",
+ "@webassemblyjs/wasm-edit": "^1.14.1",
+ "@webassemblyjs/wasm-parser": "^1.14.1",
+ "acorn": "^8.14.0",
+ "browserslist": "^4.24.0",
+ "chrome-trace-event": "^1.0.2",
+ "enhanced-resolve": "^5.17.1",
+ "es-module-lexer": "^1.2.1",
+ "eslint-scope": "5.1.1",
+ "events": "^3.2.0",
+ "glob-to-regexp": "^0.4.1",
+ "graceful-fs": "^4.2.11",
+ "json-parse-even-better-errors": "^2.3.1",
+ "loader-runner": "^4.2.0",
+ "mime-types": "^2.1.27",
+ "neo-async": "^2.6.2",
+ "schema-utils": "^4.3.0",
+ "tapable": "^2.1.1",
+ "terser-webpack-plugin": "^5.3.11",
+ "watchpack": "^2.4.1",
+ "webpack-sources": "^3.2.3"
+ },
+ "bin": {
+ "webpack": "bin/webpack.js"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ },
+ "peerDependenciesMeta": {
+ "webpack-cli": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/webpack-sources": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
+ "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/webpack/node_modules/ajv": {
+ "version": "8.17.1",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
+ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3",
+ "fast-uri": "^3.0.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/webpack/node_modules/ajv-keywords": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
+ "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3"
+ },
+ "peerDependencies": {
+ "ajv": "^8.8.2"
+ }
+ },
+ "node_modules/webpack/node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/webpack/node_modules/schema-utils": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz",
+ "integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "@types/json-schema": "^7.0.9",
+ "ajv": "^8.9.0",
+ "ajv-formats": "^2.1.1",
+ "ajv-keywords": "^5.1.0"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ }
+ }
+ }
+}
diff --git a/Cunkebao/package.json b/Cunkebao/package.json
new file mode 100644
index 00000000..da2ffd08
--- /dev/null
+++ b/Cunkebao/package.json
@@ -0,0 +1,28 @@
+{
+ "name": "cunkebao",
+ "version": "1.0.0",
+ "description": "村客宝 - 基于 uni-app 的跨平台应用",
+ "main": "main.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "keywords": [
+ "uni-app",
+ "vue",
+ "小程序",
+ "APP",
+ "H5"
+ ],
+ "author": "CunkeBao Team",
+ "license": "MIT",
+ "dependencies": {
+ "uview-ui": "^2.0.31"
+ },
+ "devDependencies": {
+ "sass": "^1.32.13",
+ "sass-loader": "^10.1.1",
+ "postcss-comment": "^2.0.0",
+ "postcss-import": "^14.0.2",
+ "autoprefixer": "^10.3.1"
+ }
+}
diff --git a/Cunkebao/pages.json b/Cunkebao/pages.json
new file mode 100644
index 00000000..b17b2301
--- /dev/null
+++ b/Cunkebao/pages.json
@@ -0,0 +1,84 @@
+{
+ "pages": [
+ {
+ "path": "pages/index/index",
+ "style": {
+ "navigationStyle": "custom",
+ "navigationBarTitleText": "首页"
+ }
+ },
+ {
+ "path": "pages/login/index",
+ "style": {
+ "navigationStyle": "custom",
+ "navigationBarTitleText": "登录",
+ "navigationBarBackgroundColor": "#ffffff",
+ "navigationBarTextStyle": "black"
+ }
+ },
+ {
+ "path": "pages/profile/index",
+ "style": {
+ "navigationStyle": "custom",
+ "navigationBarTitleText": "我的"
+ }
+ },
+ {
+ "path": "pages/agreement/user",
+ "style": {
+ "navigationBarTitleText": "用户协议",
+ "navigationBarBackgroundColor": "#ffffff",
+ "navigationBarTextStyle": "black"
+ }
+ },
+ {
+ "path": "pages/agreement/privacy",
+ "style": {
+ "navigationBarTitleText": "隐私政策",
+ "navigationBarBackgroundColor": "#ffffff",
+ "navigationBarTextStyle": "black"
+ }
+ },
+ {
+ "path": "pages/scenarios/index",
+ "style": {
+ "navigationStyle": "custom",
+ "navigationBarTitleText": "场景获客"
+ }
+ },
+ {
+ "path": "pages/scenarios/detail",
+ "style": {
+ "navigationStyle": "custom",
+ "navigationBarTitleText": "获客详情"
+ }
+ },
+ {
+ "path": "pages/scenarios/create",
+ "style": {
+ "navigationStyle": "custom",
+ "navigationBarTitleText": "新建计划"
+ }
+ },
+ {
+ "path": "pages/work/index",
+ "style": {
+ "navigationStyle": "custom",
+ "navigationBarTitleText": "工作台"
+ }
+ }
+ ],
+ "globalStyle": {
+ "navigationBarTextStyle": "black",
+ "navigationBarTitleText": "村客宝",
+ "navigationBarBackgroundColor": "#F8F8F8",
+ "backgroundColor": "#F8F8F8"
+ },
+ "easycom": {
+ "autoscan": true,
+ "custom": {
+ "^u-(.*)": "uview-ui/components/u-$1/u-$1.vue",
+ "^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue"
+ }
+ }
+}
\ No newline at end of file
diff --git a/Cunkebao/pages/agreement/privacy.vue b/Cunkebao/pages/agreement/privacy.vue
new file mode 100644
index 00000000..fe0e0da9
--- /dev/null
+++ b/Cunkebao/pages/agreement/privacy.vue
@@ -0,0 +1,201 @@
+
+
+
+
+
+ 村客宝隐私政策
+ 生效日期:2023年1月1日
+
+
+ 一、引言
+
+ 村客宝(以下简称"我们")非常重视您的隐私和个人信息保护。本隐私政策旨在向您说明我们如何收集、使用、存储、共享和保护您的个人信息,以及您享有的相关权利。
+
+
+ 请您在使用我们的服务前,仔细阅读并了解本隐私政策的全部内容。如您对本隐私政策有任何疑问,可随时联系我们的客服。
+
+
+
+
+ 二、我们收集的信息
+
+ 2.1 您主动提供的信息:当您注册账号、使用服务、参与活动或与我们沟通时,您可能会向我们提供手机号码、姓名、联系地址等信息。
+
+
+ 2.2 在您使用服务过程中收集的信息:包括设备信息、日志信息、位置信息等。这些信息是我们提供服务所必须的基础信息。
+
+
+ 2.3 来自第三方的信息:在获得您的授权或法律允许的情况下,我们可能从关联方、合作伙伴等第三方获得您的相关信息。
+
+
+
+
+ 三、我们如何使用您的信息
+
+ 3.1 向您提供服务:包括账号注册与管理、客户服务、订单管理等。
+
+
+ 3.2 产品开发与优化:我们会使用您的信息来开发和改进产品功能,提升用户体验。
+
+
+ 3.3 安全保障:我们使用您的信息用于身份验证、客户服务、安全防范、诈骗监测、存档和备份等用途。
+
+
+ 3.4 向您推送消息:我们可能会向您发送服务相关通知、活动信息等。
+
+
+
+
+ 四、信息的共享与披露
+
+ 4.1 在以下情况下,我们可能会共享您的信息:
+
+
+ - 获得您的明确同意;
+
+
+ - 根据法律法规的要求、强制性的行政或司法要求;
+
+
+ - 与我们的关联公司共享,但我们只会共享必要的信息,并要求他们遵守本隐私政策;
+
+
+ - 与授权合作伙伴共享,但我们只会共享为实现服务所必要的信息。
+
+
+
+
+ 五、信息的存储
+
+ 5.1 存储地点:我们会按照法律法规的规定,将境内收集的用户个人信息存储在中国境内。
+
+
+ 5.2 存储期限:我们仅在为实现服务目的所必需的期间内保留您的个人信息,除非法律要求或允许在更长的期间内保留这些信息。
+
+
+
+
+ 六、信息安全
+
+ 6.1 我们努力为您提供信息安全保障,以防止信息的丢失、不当使用、未经授权的访问或披露。
+
+
+ 6.2 我们使用各种安全技术和程序,以防信息的丢失、不当使用、未经授权的访问或披露。
+
+
+ 6.3 请您理解,由于技术的限制以及可能存在的各种恶意手段,即使我们已经尽最大努力加强安全措施,也不可能始终保证信息的百分之百安全。
+
+
+
+
+ 七、您的权利
+
+ 7.1 您可以通过我们提供的功能或向我们的客服提出请求,访问、更正、删除您的个人信息,或者撤回您的授权同意。
+
+
+ 7.2 请您理解,特定的业务功能和服务将需要您的信息才能得以完成,当您撤回同意或授权后,我们无法继续为您提供相应的功能和服务,也不再处理您相应的个人信息。但您撤回同意或授权的决定,不会影响我们此前基于您的授权而开展的个人信息处理。
+
+
+
+
+ 八、未成年人保护
+
+ 8.1 我们非常重视对未成年人个人信息的保护。如您为未满18周岁的未成年人,在使用我们的服务前,应在您的父母或其他监护人监护、指导下共同阅读本隐私政策,并征得您的监护人同意。
+
+
+ 8.2 如果我们发现自己在未事先获得可证实的父母或监护人同意的情况下收集了未成年人的个人信息,则会尽快删除相关数据。
+
+
+
+
+ 九、隐私政策的更新
+
+ 9.1 我们可能会不时更新本隐私政策。当我们更新隐私政策时,我们将在平台发布最新版本并更新生效日期。
+
+
+ 9.2 对于重大变更,我们还会提供更为显著的通知(包括对于特定服务,我们会通过电子邮件或站内信方式发送通知,说明隐私政策的具体变更内容)。
+
+
+ 9.3 本隐私政策所指的重大变更包括但不限于:我们的服务模式发生重大变化;个人信息共享、转让或公开披露的主要对象发生变更等。
+
+
+
+
+ 十、如何联系我们
+
+ 10.1 如您对本隐私政策有任何疑问、意见或建议,可通过以下方式与我们联系:
+
+
+ - 客服电话:400-123-4567
+
+
+ - 电子邮箱:privacy@cunkebao.com
+
+
+ 10.2 一般情况下,我们将在收到您的问题、意见或建议后15个工作日内予以回复。
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Cunkebao/pages/agreement/user.vue b/Cunkebao/pages/agreement/user.vue
new file mode 100644
index 00000000..1dcf72a9
--- /dev/null
+++ b/Cunkebao/pages/agreement/user.vue
@@ -0,0 +1,154 @@
+
+
+
+
+
+ 村客宝用户协议
+ 生效日期:2023年1月1日
+
+
+ 一、总则
+
+ 1.1 村客宝用户协议(以下简称"本协议")是您与村客宝平台(以下简称"我们")之间就村客宝平台服务等相关事宜所订立的契约。
+
+
+ 1.2 您应当在使用村客宝平台服务之前认真阅读本协议全部内容。如您对本协议有任何疑问,可随时咨询我们的客服。
+
+
+ 1.3 您点击"同意"或"下一步",或您使用村客宝平台服务,即视为您已阅读并同意签署本协议。本协议自您确认同意之时起生效。
+
+
+
+
+ 二、账号注册与使用
+
+ 2.1 您应当保证您具有完全民事行为能力,能够独立承担民事责任,并独立承担使用村客宝平台服务的一切法律责任。
+
+
+ 2.2 您注册成功后,我们将给予您一个用户账号及相应的密码,该用户账号和密码由您负责保管。
+
+
+ 2.3 您应当对您的账号负责,并就账号项下的一切行为负全部责任。因您保管不当等自身原因导致的任何损失或损害,我们不承担责任。
+
+
+
+
+ 三、服务内容
+
+ 3.1 村客宝平台服务的具体内容由我们根据实际情况提供,包括但不限于信息发布、交易撮合、数据统计等。
+
+
+ 3.2 我们有权不经事先通知,随时变更、中断或终止部分或全部的服务。
+
+
+
+
+ 四、用户义务
+
+ 4.1 您在使用村客宝平台服务时,必须遵守中华人民共和国相关法律法规。
+
+
+ 4.2 您不得利用村客宝平台服务从事违法违规行为,包括但不限于发布违法信息、侵犯他人知识产权等。
+
+
+
+
+ 五、知识产权
+
+ 5.1 村客宝平台所包含的全部智力成果,包括但不限于程序、源代码、图标、图饰、图像、图表、文字等,均受著作权法、商标法、专利法及其他知识产权法律法规的保护。
+
+
+
+
+ 六、隐私保护
+
+ 6.1 保护您的隐私是我们的重要原则,我们会采取合理的措施保护您的个人信息。
+
+
+ 6.2 有关隐私保护的详细政策,请参见《隐私政策》。
+
+
+
+
+ 七、协议修改
+
+ 7.1 我们有权随时修改本协议,并在修改后的协议生效前通过适当方式通知您。
+
+
+ 7.2 如您不同意修改后的协议,可以选择停止使用村客宝平台服务;如您继续使用村客宝平台服务,则视为您已同意修改后的协议。
+
+
+
+
+ 八、法律适用与争议解决
+
+ 8.1 本协议的成立、生效、履行、解释及纠纷解决,适用中华人民共和国大陆地区法律。
+
+
+ 8.2 若您和我们之间发生任何纠纷或争议,首先应友好协商解决;协商不成的,您同意将纠纷或争议提交至本协议签订地有管辖权的人民法院管辖。
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Cunkebao/pages/index/index.vue b/Cunkebao/pages/index/index.vue
new file mode 100644
index 00000000..3802e58b
--- /dev/null
+++ b/Cunkebao/pages/index/index.vue
@@ -0,0 +1,342 @@
+
+
+
+
+
+
+
+
+ 设备数量
+
+ 42
+
+
+
+
+
+ 微信号数量
+
+ 42
+
+
+
+
+
+ 在线微信号
+
+ 35
+
+
+
+
+
+
+
+
+
+
+
+
+ 场景获客统计
+
+
+
+
+
+ 234
+ 公众号获客
+
+
+
+
+
+
+ 167
+ 海报获客
+
+
+
+
+
+
+ 156
+ 抖音获客
+
+
+
+
+
+
+ 89
+ 小红书获客
+
+
+
+
+
+
+ 每日获客趋势
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Cunkebao/pages/login/index.vue b/Cunkebao/pages/login/index.vue
new file mode 100644
index 00000000..56854e76
--- /dev/null
+++ b/Cunkebao/pages/login/index.vue
@@ -0,0 +1,445 @@
+
+
+
+
+
+
+
+
+
+ 你所在地区仅支持 手机号 / 微信 / Apple 登录
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 已阅读并同意
+ 用户协议
+ 与
+ 隐私政策
+
+
+
+
+
+
+
+
+
+ 或
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 联系我们
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Cunkebao/pages/profile/index.vue b/Cunkebao/pages/profile/index.vue
new file mode 100644
index 00000000..8ae4d418
--- /dev/null
+++ b/Cunkebao/pages/profile/index.vue
@@ -0,0 +1,297 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 卡若
+ 账号: 84675209
+
+
+ 编辑资料
+
+
+
+
+
+
+
+
+
+ 退出登录
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Cunkebao/pages/scenarios/create.vue b/Cunkebao/pages/scenarios/create.vue
new file mode 100644
index 00000000..e91dbb50
--- /dev/null
+++ b/Cunkebao/pages/scenarios/create.vue
@@ -0,0 +1,203 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Cunkebao/pages/scenarios/detail.vue b/Cunkebao/pages/scenarios/detail.vue
new file mode 100644
index 00000000..969435d9
--- /dev/null
+++ b/Cunkebao/pages/scenarios/detail.vue
@@ -0,0 +1,482 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{channelInfo.count}}
+ 今日获客
+
+
+ {{weekTotal}}
+ 本周获客
+
+
+ {{monthTotal}}
+ 本月获客
+
+
+
+
+
+
+ 获客趋势
+
+ 本周
+ 本月
+ 全年
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.name}}
+ {{item.time}}
+
+
+
+
+
+
+
+ 暂无客户数据
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Cunkebao/pages/scenarios/index.vue b/Cunkebao/pages/scenarios/index.vue
new file mode 100644
index 00000000..d8864fef
--- /dev/null
+++ b/Cunkebao/pages/scenarios/index.vue
@@ -0,0 +1,447 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ 抖音获客
+
+
+ 今日:
+ 156
+
+
+
+ +12.5%
+
+
+
+
+
+
+
+
+
+ 小红书获客
+
+
+ 今日:
+ 89
+
+
+
+ +8.3%
+
+
+
+
+
+
+
+
+
+ 电话获客
+
+
+ 今日:
+ 42
+
+
+
+ +15.8%
+
+
+
+
+
+
+
+
+
+ 公众号获客
+
+
+ 今日:
+ 234
+
+
+
+ +15.7%
+
+
+
+
+
+
+
+
+
+ 海报获客
+
+
+ 今日:
+ 167
+
+
+
+ +10.2%
+
+
+
+
+
+
+
+
+
+ 微信群获客
+
+
+ 今日:
+ 145
+
+
+
+ +11.2%
+
+
+
+
+
+
+
+ AI智能获客
+ Beta
+
+
+
+
+
+
+
+ AI智能加友
+ 智能分析目标用户画像,自动筛选优质客户
+
+
+ 今日:
+ 245
+
+
+
+ +18.5%
+
+
+
+
+
+
+
+
+
+ AI群引流
+ 智能推聊互动,提高群活跃度和转化率
+
+
+ 今日:
+ 178
+
+
+
+ +15.2%
+
+
+
+
+
+
+
+
+
+ AI场景转化
+ 多场景智能营销,提升获客转化效果
+
+
+ 今日:
+ 134
+
+
+
+ +14.3%
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Cunkebao/pages/work/index.vue b/Cunkebao/pages/work/index.vue
new file mode 100644
index 00000000..0519ecba
--- /dev/null
+++ b/Cunkebao/pages/work/index.vue
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/Cunkebao/postcss.config.js b/Cunkebao/postcss.config.js
new file mode 100644
index 00000000..902a44fd
--- /dev/null
+++ b/Cunkebao/postcss.config.js
@@ -0,0 +1,23 @@
+const path = require('path')
+
+module.exports = {
+ parser: require('postcss-comment'),
+ plugins: [
+ require('postcss-import')({
+ resolve(id, basedir, importOptions) {
+ if (id.startsWith('~@/')) {
+ return path.resolve(process.env.UNI_INPUT_DIR, id.substr(3))
+ } else if (id.startsWith('@/')) {
+ return path.resolve(process.env.UNI_INPUT_DIR, id.substr(2))
+ } else if (id.startsWith('/') && !id.startsWith('//')) {
+ return path.resolve(process.env.UNI_INPUT_DIR, id.substr(1))
+ }
+ return id
+ }
+ }),
+ require('autoprefixer')({
+ remove: process.env.UNI_PLATFORM !== 'h5'
+ }),
+ require('@dcloudio/vue-cli-plugin-uni/packages/postcss')
+ ]
+}
\ No newline at end of file
diff --git a/Cunkebao/static/fonts/fonts.css b/Cunkebao/static/fonts/fonts.css
new file mode 100644
index 00000000..c09b4e0b
--- /dev/null
+++ b/Cunkebao/static/fonts/fonts.css
@@ -0,0 +1,27 @@
+@font-face {
+ font-family: 'Digital-Bold';
+ src: url('https://cdn.jsdelivr.net/npm/alibaba-puhuiti@1.0.0/AlibabaPuHuiTi-Bold.ttf') format('truetype');
+ font-weight: bold;
+ font-style: normal;
+ font-display: swap;
+}
+
+@font-face {
+ font-family: 'Digital-Medium';
+ src: url('https://cdn.jsdelivr.net/npm/alibaba-puhuiti@1.0.0/AlibabaPuHuiTi-Medium.ttf') format('truetype');
+ font-weight: normal;
+ font-style: normal;
+ font-display: swap;
+}
+
+.digital-text {
+ font-family: 'Digital-Bold', sans-serif;
+ font-weight: bold;
+ letter-spacing: 0.5px;
+}
+
+.digital-number {
+ font-family: 'Digital-Bold', sans-serif;
+ font-weight: bold;
+ letter-spacing: 0.5px;
+}
\ No newline at end of file
diff --git a/Cunkebao/static/images/apple.png b/Cunkebao/static/images/apple.png
new file mode 100644
index 00000000..d6b26475
--- /dev/null
+++ b/Cunkebao/static/images/apple.png
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/Cunkebao/static/images/icons/heartbeat.svg b/Cunkebao/static/images/icons/heartbeat.svg
new file mode 100644
index 00000000..38006377
--- /dev/null
+++ b/Cunkebao/static/images/icons/heartbeat.svg
@@ -0,0 +1,16 @@
+
+
\ No newline at end of file
diff --git a/Cunkebao/static/images/icons/smartphone.svg b/Cunkebao/static/images/icons/smartphone.svg
new file mode 100644
index 00000000..556da438
--- /dev/null
+++ b/Cunkebao/static/images/icons/smartphone.svg
@@ -0,0 +1,21 @@
+
+
\ No newline at end of file
diff --git a/Cunkebao/static/images/icons/team.svg b/Cunkebao/static/images/icons/team.svg
new file mode 100644
index 00000000..8d82f6e9
--- /dev/null
+++ b/Cunkebao/static/images/icons/team.svg
@@ -0,0 +1,35 @@
+
+
\ No newline at end of file
diff --git a/Cunkebao/static/images/icons/users.svg b/Cunkebao/static/images/icons/users.svg
new file mode 100644
index 00000000..a623fe4b
--- /dev/null
+++ b/Cunkebao/static/images/icons/users.svg
@@ -0,0 +1,24 @@
+
+
\ No newline at end of file
diff --git a/Cunkebao/static/images/icons/wechat.svg b/Cunkebao/static/images/icons/wechat.svg
new file mode 100644
index 00000000..1c32bafc
--- /dev/null
+++ b/Cunkebao/static/images/icons/wechat.svg
@@ -0,0 +1,21 @@
+
+
\ No newline at end of file
diff --git a/Cunkebao/static/images/tabbar/home-active.png b/Cunkebao/static/images/tabbar/home-active.png
new file mode 100644
index 00000000..258b9b8b
--- /dev/null
+++ b/Cunkebao/static/images/tabbar/home-active.png
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/Cunkebao/static/images/tabbar/home.png b/Cunkebao/static/images/tabbar/home.png
new file mode 100644
index 00000000..a8a4961e
--- /dev/null
+++ b/Cunkebao/static/images/tabbar/home.png
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/Cunkebao/static/images/tabbar/market-active.png b/Cunkebao/static/images/tabbar/market-active.png
new file mode 100644
index 00000000..0519ecba
--- /dev/null
+++ b/Cunkebao/static/images/tabbar/market-active.png
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/Cunkebao/static/images/tabbar/market.png b/Cunkebao/static/images/tabbar/market.png
new file mode 100644
index 00000000..0519ecba
--- /dev/null
+++ b/Cunkebao/static/images/tabbar/market.png
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/Cunkebao/static/images/tabbar/profile-active.png b/Cunkebao/static/images/tabbar/profile-active.png
new file mode 100644
index 00000000..0519ecba
--- /dev/null
+++ b/Cunkebao/static/images/tabbar/profile-active.png
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/Cunkebao/static/images/tabbar/profile.png b/Cunkebao/static/images/tabbar/profile.png
new file mode 100644
index 00000000..0519ecba
--- /dev/null
+++ b/Cunkebao/static/images/tabbar/profile.png
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/Cunkebao/static/images/tabbar/work-active.png b/Cunkebao/static/images/tabbar/work-active.png
new file mode 100644
index 00000000..0519ecba
--- /dev/null
+++ b/Cunkebao/static/images/tabbar/work-active.png
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/Cunkebao/static/images/tabbar/work.png b/Cunkebao/static/images/tabbar/work.png
new file mode 100644
index 00000000..0519ecba
--- /dev/null
+++ b/Cunkebao/static/images/tabbar/work.png
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/Cunkebao/uni.scss b/Cunkebao/uni.scss
new file mode 100644
index 00000000..700a1e67
--- /dev/null
+++ b/Cunkebao/uni.scss
@@ -0,0 +1,68 @@
+/* 主题色变量 */
+$primary-color: #4080ff;
+$success-color: #07c160;
+$warning-color: #ff9900;
+$error-color: #fa5151;
+$info-color: #909399;
+
+/* 文字颜色 */
+$text-color-main: #333333;
+$text-color-regular: #666666;
+$text-color-secondary: #999999;
+$text-color-placeholder: #c0c4cc;
+$text-color-white: #ffffff;
+
+/* 边框颜色 */
+$border-color-base: #dcdfe6;
+$border-color-light: #e4e7ed;
+$border-color-lighter: #ebeef5;
+$border-color-extra-light: #f2f6fc;
+
+/* 背景颜色 */
+$bg-color: #f9fafb;
+$bg-color-white: #ffffff;
+$bg-color-primary: rgba(64, 128, 255, 0.1);
+$bg-color-success: rgba(7, 193, 96, 0.1);
+$bg-color-warning: rgba(255, 153, 0, 0.1);
+$bg-color-error: rgba(250, 81, 81, 0.1);
+
+/* 字体大小 */
+$font-size-xs: 20rpx;
+$font-size-sm: 24rpx;
+$font-size-base: 28rpx;
+$font-size-medium: 32rpx;
+$font-size-lg: 36rpx;
+$font-size-xl: 40rpx;
+$font-size-xxl: 48rpx;
+
+/* 圆角大小 */
+$border-radius-sm: 4rpx;
+$border-radius-base: 8rpx;
+$border-radius-lg: 16rpx;
+$border-radius-circle: 50%;
+
+/* 间距大小 */
+$spacing-xs: 10rpx;
+$spacing-sm: 20rpx;
+$spacing-base: 30rpx;
+$spacing-lg: 40rpx;
+$spacing-xl: 50rpx;
+
+/* 字体加粗 */
+$font-weight-normal: 400;
+$font-weight-medium: 500;
+$font-weight-bold: 700;
+
+/* 阴影 */
+$shadow-sm: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
+$shadow-base: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
+$shadow-lg: 0 8rpx 16rpx rgba(0, 0, 0, 0.1);
+
+/* 基础动画 */
+$animation-duration-fast: 0.2s;
+$animation-duration-base: 0.3s;
+$animation-duration-slow: 0.4s;
+$animation-timing-function-base: ease-in-out;
+
+/* 导入uView的变量 */
+@import 'uview-ui/theme.scss';
\ No newline at end of file
diff --git a/Cunkebao/utils/auth.js b/Cunkebao/utils/auth.js
new file mode 100644
index 00000000..896a29c5
--- /dev/null
+++ b/Cunkebao/utils/auth.js
@@ -0,0 +1,96 @@
+/**
+ * 认证相关工具函数
+ */
+
+const TOKEN_KEY = 'token';
+const TOKEN_EXPIRES_KEY = 'token_expires';
+const USER_INFO_KEY = 'user_info';
+
+/**
+ * 设置Token
+ * @param {string} token 令牌
+ * @param {number} expires 过期时间(秒)
+ */
+function setToken(token, expires = 7200) {
+ uni.setStorageSync(TOKEN_KEY, token);
+
+ // 计算过期时间点(当前时间 + 有效期)
+ const expiresTime = Math.floor(Date.now() / 1000) + expires;
+ uni.setStorageSync(TOKEN_EXPIRES_KEY, expiresTime);
+}
+
+/**
+ * 获取Token
+ * @returns {string} token值
+ */
+function getToken() {
+ return uni.getStorageSync(TOKEN_KEY);
+}
+
+/**
+ * 移除Token
+ */
+function removeToken() {
+ uni.removeStorageSync(TOKEN_KEY);
+ uni.removeStorageSync(TOKEN_EXPIRES_KEY);
+}
+
+/**
+ * 设置用户信息
+ * @param {Object} userInfo 用户信息
+ */
+function setUserInfo(userInfo) {
+ uni.setStorageSync(USER_INFO_KEY, JSON.stringify(userInfo));
+}
+
+/**
+ * 获取用户信息
+ * @returns {Object} 用户信息
+ */
+function getUserInfo() {
+ const userInfo = uni.getStorageSync(USER_INFO_KEY);
+ return userInfo ? JSON.parse(userInfo) : null;
+}
+
+/**
+ * 移除用户信息
+ */
+function removeUserInfo() {
+ uni.removeStorageSync(USER_INFO_KEY);
+}
+
+/**
+ * 移除所有认证信息
+ */
+function removeAll() {
+ removeToken();
+ removeUserInfo();
+}
+
+/**
+ * 判断是否已登录
+ * @returns {boolean} 是否已登录
+ */
+function isLogin() {
+ const token = getToken();
+ // 如果没有token,直接返回未登录
+ if (!token) return false;
+
+ // 检查token是否过期
+ const expiresTime = uni.getStorageSync(TOKEN_EXPIRES_KEY) || 0;
+ const nowTime = Math.floor(Date.now() / 1000);
+
+ // 如果当前时间超过过期时间,则返回未登录
+ return nowTime < expiresTime;
+}
+
+export default {
+ setToken,
+ getToken,
+ removeToken,
+ setUserInfo,
+ getUserInfo,
+ removeUserInfo,
+ removeAll,
+ isLogin
+};
\ No newline at end of file
diff --git a/Cunkebao/utils/common.js b/Cunkebao/utils/common.js
new file mode 100644
index 00000000..69fa5a2f
--- /dev/null
+++ b/Cunkebao/utils/common.js
@@ -0,0 +1,141 @@
+/**
+ * 通用工具函数集合
+ */
+
+/**
+ * 格式化日期
+ * @param {Date|string|number} date 日期对象/日期字符串/时间戳
+ * @param {string} format 格式化模板,如:YYYY-MM-DD HH:mm:ss
+ * @returns {string} 格式化后的日期字符串
+ */
+function formatDate(date, format = 'YYYY-MM-DD HH:mm:ss') {
+ if (!date) return '';
+
+ // 如果是时间戳或字符串,转为日期对象
+ if (typeof date === 'string' || typeof date === 'number') {
+ date = new Date(date);
+ }
+
+ // 定义替换规则
+ const rules = {
+ 'YYYY': date.getFullYear(),
+ 'MM': padZero(date.getMonth() + 1),
+ 'DD': padZero(date.getDate()),
+ 'HH': padZero(date.getHours()),
+ 'mm': padZero(date.getMinutes()),
+ 'ss': padZero(date.getSeconds())
+ };
+
+ // 替换
+ return format.replace(/(YYYY|MM|DD|HH|mm|ss)/g, function(key) {
+ return rules[key];
+ });
+}
+
+/**
+ * 补零
+ * @param {number} num 数字
+ * @returns {string} 补零后的字符串
+ */
+function padZero(num) {
+ return String(num).padStart(2, '0');
+}
+
+/**
+ * 格式化手机号
+ * @param {string} mobile 手机号
+ * @returns {string} 格式化后的手机号,如:138****8888
+ */
+function formatMobile(mobile) {
+ if (!mobile) return '';
+ return mobile.replace(/^(\d{3})\d{4}(\d{4})$/, '$1****$2');
+}
+
+/**
+ * 生成UUID
+ * @returns {string} UUID
+ */
+function generateUUID() {
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
+ const r = Math.random() * 16 | 0;
+ const v = c === 'x' ? r : (r & 0x3 | 0x8);
+ return v.toString(16);
+ });
+}
+
+/**
+ * 深度克隆对象
+ * @param {Object} obj 需要克隆的对象
+ * @returns {Object} 克隆后的对象
+ */
+function deepClone(obj) {
+ if (obj === null || typeof obj !== 'object') {
+ return obj;
+ }
+
+ // 处理日期
+ if (obj instanceof Date) {
+ return new Date(obj.getTime());
+ }
+
+ // 处理数组
+ if (obj instanceof Array) {
+ return obj.map(item => deepClone(item));
+ }
+
+ // 处理对象
+ const clonedObj = {};
+ for (const key in obj) {
+ if (obj.hasOwnProperty(key)) {
+ clonedObj[key] = deepClone(obj[key]);
+ }
+ }
+
+ return clonedObj;
+}
+
+/**
+ * 防抖函数
+ * @param {Function} fn 需要防抖的函数
+ * @param {number} delay 延迟时间,单位ms
+ * @returns {Function} 防抖后的函数
+ */
+function debounce(fn, delay = 300) {
+ let timer = null;
+
+ return function(...args) {
+ if (timer) clearTimeout(timer);
+
+ timer = setTimeout(() => {
+ fn.apply(this, args);
+ }, delay);
+ };
+}
+
+/**
+ * 节流函数
+ * @param {Function} fn 需要节流的函数
+ * @param {number} delay 延迟时间,单位ms
+ * @returns {Function} 节流后的函数
+ */
+function throttle(fn, delay = 300) {
+ let lastTime = 0;
+
+ return function(...args) {
+ const now = Date.now();
+
+ if (now - lastTime >= delay) {
+ fn.apply(this, args);
+ lastTime = now;
+ }
+ };
+}
+
+export default {
+ formatDate,
+ formatMobile,
+ generateUUID,
+ deepClone,
+ debounce,
+ throttle
+};
\ No newline at end of file
diff --git a/Cunkebao/utils/request.js b/Cunkebao/utils/request.js
new file mode 100644
index 00000000..4359f87b
--- /dev/null
+++ b/Cunkebao/utils/request.js
@@ -0,0 +1,132 @@
+import Auth from './auth';
+
+// 服务器地址
+const BASE_URL = process.env.NODE_ENV === 'development'
+ ? 'http://localhost:8080'
+ : 'https://api.example.com';
+
+// 请求超时时间
+const TIMEOUT = 10000;
+
+/**
+ * 请求拦截器
+ * @param {Object} config 请求配置
+ * @returns {Object} 处理后的请求配置
+ */
+function requestInterceptor(config) {
+ // 获取 token
+ const token = uni.getStorageSync('token');
+
+ // 如果有 token,则带上请求头
+ if (token) {
+ config.header = {
+ ...config.header,
+ 'Authorization': `Bearer ${token}`
+ };
+ }
+
+ // 打印请求日志
+ console.log('请求地址:', `${config.baseURL || BASE_URL}${config.url}`);
+
+ return config;
+}
+
+/**
+ * 响应拦截器
+ * @param {Object} response 响应数据
+ * @returns {Object|Promise} 处理后的响应数据或Promise
+ */
+function responseInterceptor(response) {
+ // 未登录或token失效 - 取消登录拦截
+ if (response.data.code === 401) {
+ // 只在控制台打印信息,不进行拦截
+ console.log('登录已过期,但不进行拦截');
+
+ /*
+ // 以下代码已注释,取消登录拦截
+ // 清除登录信息
+ Auth.removeToken();
+ Auth.removeUserInfo();
+
+ // 跳转到登录页
+ uni.reLaunch({
+ url: '/pages/login/index'
+ });
+
+ return Promise.reject(new Error('登录已过期,请重新登录'));
+ */
+
+ // 直接返回响应,不拦截
+ return response.data;
+ }
+
+ // token需要刷新 - 取消登录拦截
+ if (response.data.code === 410) {
+ // 只在控制台打印信息,不进行拦截
+ console.log('Token需要刷新,但不进行拦截');
+
+ /*
+ // 以下代码已注释,取消登录拦截
+ // 处理token刷新逻辑,这里简化处理
+ uni.reLaunch({
+ url: '/pages/login/index'
+ });
+
+ return Promise.reject(new Error('登录已过期,请重新登录'));
+ */
+
+ // 直接返回响应,不拦截
+ return response.data;
+ }
+
+ return response.data;
+}
+
+/**
+ * 统一请求函数
+ * @param {Object} options 请求选项
+ * @returns {Promise} 请求结果
+ */
+function request(options) {
+ // 合并请求选项
+ const config = {
+ baseURL: BASE_URL,
+ timeout: TIMEOUT,
+ header: {
+ 'Content-Type': 'application/json'
+ },
+ ...options
+ };
+
+ // 请求拦截
+ const interceptedConfig = requestInterceptor(config);
+
+ // 发起请求
+ return new Promise((resolve, reject) => {
+ uni.request({
+ url: `${interceptedConfig.baseURL}${interceptedConfig.url}`,
+ method: interceptedConfig.method || 'GET',
+ data: interceptedConfig.data,
+ header: interceptedConfig.header,
+ timeout: interceptedConfig.timeout,
+ success: (res) => {
+ try {
+ const result = responseInterceptor(res);
+ resolve(result);
+ } catch (error) {
+ reject(error);
+ }
+ },
+ fail: (err) => {
+ uni.showToast({
+ title: '网络请求失败',
+ icon: 'none',
+ duration: 2000
+ });
+ reject(err);
+ }
+ });
+ });
+}
+
+export default request;
\ No newline at end of file
diff --git a/Server/.env b/Server/.env
index cf5b3d6e..9a16c12e 100644
--- a/Server/.env
+++ b/Server/.env
@@ -4,7 +4,7 @@ trace = true
[database]
type = mysql
-hostname = 127.0.0.1
+hostname = 103.144.2.26
database = yi_54iis_com
username = yi_54iis_com
password = c1RbMwrZCCyxF1bC
diff --git a/Server/application/common/config/route.php b/Server/application/common/config/route.php
index e8bb5000..c7f823d8 100644
--- a/Server/application/common/config/route.php
+++ b/Server/application/common/config/route.php
@@ -13,4 +13,10 @@ Route::group('v1/auth', function () {
// 需要JWT认证的接口
Route::get('info', 'app\\common\\controller\\Auth@info')->middleware(['jwt']); // 获取用户信息
Route::post('refresh', 'app\\common\\controller\\Auth@refresh')->middleware(['jwt']); // 刷新令牌
-});
\ No newline at end of file
+});
+
+// 附件上传相关路由
+Route::group('v1/', function () {
+ Route::post('attachment/upload', 'app\\common\\controller\\Attachment@upload'); // 上传附件
+ Route::get('attachment/:id', 'app\\common\\controller\\Attachment@info'); // 获取附件信息
+})->middleware(['jwt']);
\ No newline at end of file
diff --git a/Server/application/common/controller/Attachment.php b/Server/application/common/controller/Attachment.php
new file mode 100644
index 00000000..78bbb759
--- /dev/null
+++ b/Server/application/common/controller/Attachment.php
@@ -0,0 +1,140 @@
+ 400,
+ 'msg' => '请选择要上传的文件'
+ ]);
+ }
+
+ // 验证文件
+ $validate = \think\facade\Validate::rule([
+ 'file' => [
+ 'fileSize' => 10485760, // 10MB
+ 'fileExt' => 'jpg,jpeg,png,gif,doc,docx,pdf,zip,rar',
+ 'fileMime' => 'image/jpeg,image/png,image/gif,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/pdf,application/zip,application/x-rar-compressed'
+ ]
+ ]);
+
+ if (!$validate->check(['file' => $file])) {
+ return json([
+ 'code' => 400,
+ 'msg' => $validate->getError()
+ ]);
+ }
+
+ // 生成文件hash
+ $hashKey = md5_file($file->getRealPath());
+
+ // 检查文件是否已存在
+ $existFile = AttachmentModel::getByHashKey($hashKey);
+ if ($existFile) {
+ return json([
+ 'code' => 200,
+ 'msg' => '文件已存在',
+ 'data' => [
+ 'id' => $existFile['id'],
+ 'name' => $existFile['name'],
+ 'url' => $existFile['source']
+ ]
+ ]);
+ }
+
+ // 生成OSS对象名称
+ $objectName = AliyunOSS::generateObjectName($file->getOriginalName());
+
+ // 上传到OSS
+ $result = AliyunOSS::uploadFile($file->getRealPath(), $objectName);
+
+ if (!$result['success']) {
+ return json([
+ 'code' => 500,
+ 'msg' => '文件上传失败:' . $result['error']
+ ]);
+ }
+
+ // 保存到数据库
+ $attachmentData = [
+ 'name' => Request::param('name') ?: $file->getOriginalName(),
+ 'hash_key' => $hashKey,
+ 'server' => 'aliyun_oss',
+ 'source' => $result['url'],
+ 'size' => $result['size'],
+ 'suffix' => pathinfo($file->getOriginalName(), PATHINFO_EXTENSION)
+ ];
+
+ $attachmentId = AttachmentModel::addAttachment($attachmentData);
+
+ if (!$attachmentId) {
+ return json([
+ 'code' => 500,
+ 'msg' => '保存附件信息失败'
+ ]);
+ }
+
+ return json([
+ 'code' => 200,
+ 'msg' => '上传成功',
+ 'data' => [
+ 'id' => $attachmentId,
+ 'name' => $attachmentData['name'],
+ 'url' => $attachmentData['source']
+ ]
+ ]);
+
+ } catch (\Exception $e) {
+ return json([
+ 'code' => 500,
+ 'msg' => '上传失败:' . $e->getMessage()
+ ]);
+ }
+ }
+
+ /**
+ * 获取附件信息
+ * @param int $id 附件ID
+ * @return \think\response\Json
+ */
+ public function info($id)
+ {
+ try {
+ $attachment = AttachmentModel::find($id);
+
+ if (!$attachment) {
+ return json([
+ 'code' => 404,
+ 'msg' => '附件不存在'
+ ]);
+ }
+
+ return json([
+ 'code' => 200,
+ 'msg' => '获取成功',
+ 'data' => $attachment
+ ]);
+
+ } catch (\Exception $e) {
+ return json([
+ 'code' => 500,
+ 'msg' => '获取失败:' . $e->getMessage()
+ ]);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Server/application/common/model/Attachment.php b/Server/application/common/model/Attachment.php
new file mode 100644
index 00000000..cf3a8a57
--- /dev/null
+++ b/Server/application/common/model/Attachment.php
@@ -0,0 +1,55 @@
+ 'integer',
+ 'dl_count' => 'integer',
+ 'size' => 'integer',
+ 'scene' => 'integer',
+ 'create_at' => 'datetime',
+ 'update_at' => 'datetime',
+ 'delete_at' => 'datetime'
+ ];
+
+ /**
+ * 添加附件记录
+ * @param array $data 附件数据
+ * @return int|bool
+ */
+ public static function addAttachment($data)
+ {
+ $attachment = new self();
+ return $attachment->allowField(true)->save($data);
+ }
+
+ /**
+ * 根据hash_key获取附件
+ * @param string $hashKey
+ * @return array|null
+ */
+ public static function getByHashKey($hashKey)
+ {
+ return self::where('hash_key', $hashKey)
+ ->where('delete_at', null)
+ ->find();
+ }
+}
\ No newline at end of file
diff --git a/Server/application/common/util/AliyunOSS.php b/Server/application/common/util/AliyunOSS.php
new file mode 100644
index 00000000..a8ec91c8
--- /dev/null
+++ b/Server/application/common/util/AliyunOSS.php
@@ -0,0 +1,77 @@
+getMessage());
+ }
+ }
+
+ /**
+ * 上传文件到OSS
+ * @param string $filePath 本地文件路径
+ * @param string $objectName OSS对象名称
+ * @return array
+ * @throws OssException
+ */
+ public static function uploadFile($filePath, $objectName)
+ {
+ try {
+ $client = self::getClient();
+
+ // 上传文件
+ $result = $client->uploadFile(self::BUCKET, $objectName, $filePath);
+
+ // 获取文件访问URL
+ $url = $client->signUrl(self::BUCKET, $objectName, 3600);
+
+ return [
+ 'success' => true,
+ 'url' => $url,
+ 'object_name' => $objectName,
+ 'size' => filesize($filePath),
+ 'mime_type' => mime_content_type($filePath)
+ ];
+ } catch (OssException $e) {
+ return [
+ 'success' => false,
+ 'error' => $e->getMessage()
+ ];
+ }
+ }
+
+ /**
+ * 生成OSS对象名称
+ * @param string $originalName 原始文件名
+ * @return string
+ */
+ public static function generateObjectName($originalName)
+ {
+ $ext = pathinfo($originalName, PATHINFO_EXTENSION);
+ $name = md5(uniqid(mt_rand(), true));
+ return date('Y/m/d/') . $name . '.' . $ext;
+ }
+}
\ No newline at end of file
diff --git a/Server/application/common/AliyunSMS.php b/Server/application/common/util/AliyunSMS.php
similarity index 98%
rename from Server/application/common/AliyunSMS.php
rename to Server/application/common/util/AliyunSMS.php
index 3a920d4b..e742591a 100644
--- a/Server/application/common/AliyunSMS.php
+++ b/Server/application/common/util/AliyunSMS.php
@@ -1,6 +1,6 @@
middleware(['jwt']);
\ No newline at end of file
diff --git a/Server/application/devices/controller/DeviceWechat.php b/Server/application/devices/controller/DeviceWechat.php
new file mode 100644
index 00000000..5e151423
--- /dev/null
+++ b/Server/application/devices/controller/DeviceWechat.php
@@ -0,0 +1,476 @@
+ 200,
+ 'msg' => '获取成功',
+ 'data' => [
+ 'count' => $count
+ ]
+ ]);
+ } catch (\Exception $e) {
+ return json([
+ 'code' => 500,
+ 'msg' => '获取失败:' . $e->getMessage()
+ ]);
+ }
+ }
+
+ /**
+ * 获取有登录微信的设备数量
+ * @return \think\response\Json
+ */
+ public function deviceCount()
+ {
+ try {
+ // 获取有登录微信的设备数量
+ $count = WechatAccount::getDeviceWithWechatCount();
+
+ return json([
+ 'code' => 200,
+ 'msg' => '获取成功',
+ 'data' => [
+ 'count' => $count
+ ]
+ ]);
+ } catch (\Exception $e) {
+ return json([
+ 'code' => 500,
+ 'msg' => '获取失败:' . $e->getMessage()
+ ]);
+ }
+ }
+
+ /**
+ * 刷新设备微信状态
+ * @return \think\response\Json
+ */
+ public function refresh()
+ {
+ try {
+ return json([
+ 'code' => 200,
+ 'msg' => '刷新成功',
+ 'data' => []
+ ]);
+ } catch (\Exception $e) {
+ return json([
+ 'code' => 500,
+ 'msg' => '获取失败:' . $e->getMessage()
+ ]);
+ }
+ }
+
+ /**
+ * 获取在线微信账号列表
+ * @return \think\response\Json
+ */
+ public function index()
+ {
+ try {
+ // 获取查询条件
+ $where = [];
+
+ // 微信ID
+ $wechatId = Request::param('wechat_id');
+ if (!empty($wechatId)) {
+ $where['wechatId'] = ['like', "%{$wechatId}%"];
+ }
+
+ // 昵称
+ $nickname = Request::param('nickname');
+ if (!empty($nickname)) {
+ $where['nickname|accountNickname'] = ['like', "%{$nickname}%"];
+ }
+
+ // 获取分页参数
+ $page = (int)Request::param('page', 1);
+ $limit = (int)Request::param('limit', 10);
+
+ // 获取排序参数
+ $sort = Request::param('sort', 'id');
+ $order = Request::param('order', 'desc');
+
+ // 获取在线微信账号列表
+ $list = WechatAccount::getOnlineWechatList($where, "{$sort} {$order}", $page, $limit);
+
+ // 处理返回数据
+ $data = [];
+ foreach ($list->items() as $item) {
+ // 计算今日可添加好友数量(这里使用一个示例算法,你可以根据实际需求修改)
+ $canAddFriendCount = 30 - (isset($item['yesterdayMsgCount']) ? intval($item['yesterdayMsgCount']) : 0);
+ if ($canAddFriendCount < 0) {
+ $canAddFriendCount = 0;
+ }
+
+ // 计算今日新增好友数量(示例数据,实际需要从数据库获取或通过其他方式计算)
+ // 这里只是一个示例,你需要根据实际情况替换
+ $todayNewFriendCount = mt_rand(0, 10); // 随机生成0-10的数字作为示例
+
+ $data[] = [
+ 'id' => $item['id'],
+ 'wechatId' => $item['wechatId'],
+ 'nickname' => $item['nickname'] ?: $item['accountNickname'],
+ 'avatar' => $item['avatar'],
+ 'accountUserName' => $item['accountUserName'],
+ 'status' => $item['wechatAlive'] ? '在线' : '离线',
+ 'deviceStatus' => $item['deviceAlive'] ? '在线' : '离线',
+ 'totalFriend' => $item['totalFriend'],
+ 'canAddFriendCount' => $canAddFriendCount,
+ 'deviceInfo' => $item['imei'] . ($item['deviceMemo'] ? " ({$item['deviceMemo']})" : ''),
+ 'todayNewFriendCount' => $todayNewFriendCount
+ ];
+ }
+
+ return json([
+ 'code' => 200,
+ 'msg' => '获取成功',
+ 'data' => [
+ 'total' => $list->total(),
+ 'list' => $data
+ ]
+ ]);
+ } catch (\Exception $e) {
+ return json([
+ 'code' => 500,
+ 'msg' => '获取失败:' . $e->getMessage()
+ ]);
+ }
+ }
+
+ /**
+ * 获取微信号详情
+ * @param int $id 微信号ID
+ * @return \think\response\Json
+ */
+ public function detail($id)
+ {
+ try {
+ // 获取微信号基本信息
+ $wechat = WechatAccount::where('id', $id)
+ ->where('isDeleted', 0)
+ ->find();
+
+ if (!$wechat) {
+ return json([
+ 'code' => 404,
+ 'msg' => '微信号不存在'
+ ]);
+ }
+
+ // 计算账号年龄(从创建时间到现在)
+ $accountAge = 0;
+ if ($wechat['createTime']) {
+ $createTime = strtotime($wechat['createTime']);
+ $now = time();
+ $accountAge = floor(($now - $createTime) / (24 * 3600));
+ }
+
+ // 计算活跃程度(根据消息数)
+ $activityLevel = '低';
+ if ($wechat['thirtyDayMsgCount'] > 1000) {
+ $activityLevel = '高';
+ } elseif ($wechat['thirtyDayMsgCount'] > 500) {
+ $activityLevel = '中';
+ }
+
+ // 评估账号权重(示例算法)
+ $weight = 0;
+ // 基础权重
+ $weight += 10;
+ // 好友数量权重
+ $weight += min($wechat['totalFriend'] / 100, 20);
+ // 活跃度权重
+ $weight += min($wechat['thirtyDayMsgCount'] / 100, 20);
+ // 账号年龄权重
+ $weight += min($accountAge / 30, 10);
+ // 在线状态权重
+ if ($wechat['wechatAlive']) {
+ $weight += 5;
+ }
+
+ // 获取限制记录(示例数据,实际需要从数据库获取)
+ $restrictions = [
+ [
+ 'type' => '添加好友限制',
+ 'reason' => '频繁添加好友',
+ 'startTime' => date('Y-m-d H:i:s', strtotime('-1 day')),
+ 'endTime' => date('Y-m-d H:i:s', strtotime('+1 day'))
+ ]
+ ];
+
+ // 获取微信好友列表
+ $friends = Db::table('tk_wechat_friend')
+ ->where('wechatAccountId', $id)
+ ->where('isDeleted', 0)
+ ->field([
+ 'id',
+ 'wechatId',
+ 'nickname',
+ 'avatar',
+ 'gender',
+ 'region',
+ 'signature',
+ 'labels',
+ 'createTime'
+ ])
+ ->select();
+
+ // 处理返回数据
+ $data = [
+ 'basicInfo' => [
+ 'id' => $wechat['id'],
+ 'wechatId' => $wechat['wechatId'],
+ 'nickname' => $wechat['nickname'] ?: $wechat['accountNickname'],
+ 'avatar' => $wechat['avatar'],
+ 'status' => $wechat['wechatAlive'] ? '在线' : '离线',
+ 'deviceStatus' => $wechat['deviceAlive'] ? '在线' : '离线',
+ 'deviceInfo' => $wechat['imei'] . ($wechat['deviceMemo'] ? " ({$wechat['deviceMemo']})" : ''),
+ 'gender' => $wechat['gender'],
+ 'region' => $wechat['region'],
+ 'signature' => $wechat['signature']
+ ],
+ 'statistics' => [
+ 'totalFriend' => $wechat['totalFriend'],
+ 'maleFriend' => $wechat['maleFriend'],
+ 'femaleFriend' => $wechat['femaleFriend'],
+ 'canAddFriendCount' => 30 - (isset($wechat['yesterdayMsgCount']) ? intval($wechat['yesterdayMsgCount']) : 0),
+ 'yesterdayMsgCount' => $wechat['yesterdayMsgCount'],
+ 'sevenDayMsgCount' => $wechat['sevenDayMsgCount'],
+ 'thirtyDayMsgCount' => $wechat['thirtyDayMsgCount']
+ ],
+ 'accountInfo' => [
+ 'age' => $accountAge,
+ 'activityLevel' => $activityLevel,
+ 'weight' => round($weight, 2),
+ 'createTime' => $wechat['createTime'],
+ 'lastUpdateTime' => $wechat['updateTime']
+ ],
+ 'restrictions' => $restrictions,
+ 'friends' => $friends
+ ];
+
+ return json([
+ 'code' => 200,
+ 'msg' => '获取成功',
+ 'data' => $data
+ ]);
+ } catch (\Exception $e) {
+ return json([
+ 'code' => 500,
+ 'msg' => '获取失败:' . $e->getMessage()
+ ]);
+ }
+ }
+
+ /**
+ * 微信好友转移
+ * 将一个微信号的好友转移至另一个在线微信号
+ *
+ * @return \think\response\Json
+ */
+ public function transferFriends()
+ {
+ try {
+ // 获取请求参数
+ $sourceWechatId = Request::param('source_id'); // 源微信账号ID
+ $targetWechatId = Request::param('target_id'); // 目标微信账号ID
+
+ // 参数验证
+ if (empty($sourceWechatId) || empty($targetWechatId)) {
+ return json([
+ 'code' => 400,
+ 'msg' => '参数错误:源微信账号ID和目标微信账号ID不能为空'
+ ]);
+ }
+
+ // 检查源微信账号是否存在
+ $sourceWechat = WechatAccount::where('id', $sourceWechatId)
+ ->where('isDeleted', 0)
+ ->find();
+
+ if (!$sourceWechat) {
+ return json([
+ 'code' => 404,
+ 'msg' => '源微信账号不存在'
+ ]);
+ }
+
+ // 检查目标微信账号是否存在且在线
+ $targetWechat = WechatAccount::where('id', $targetWechatId)
+ ->where('isDeleted', 0)
+ ->where('wechatAlive', 1)
+ ->where('deviceAlive', 1)
+ ->find();
+
+ if (!$targetWechat) {
+ return json([
+ 'code' => 404,
+ 'msg' => '目标微信账号不存在或不在线'
+ ]);
+ }
+
+ // 获取源微信账号的好友列表
+ $friends = Db::table('tk_wechat_friend')
+ ->where('wechatAccountId', $sourceWechatId)
+ ->where('isDeleted', 0)
+ ->select();
+
+ // 统计好友数量
+ $totalFriends = count($friends);
+
+ if ($totalFriends == 0) {
+ return json([
+ 'code' => 400,
+ 'msg' => '源微信账号没有可转移的好友'
+ ]);
+ }
+
+ // 开始事务
+ Db::startTrans();
+
+ try {
+ $successCount = 0;
+ $failCount = 0;
+ $duplicateCount = 0;
+ $failList = [];
+
+ foreach ($friends as $friend) {
+ // 检查目标微信账号是否已经有此好友
+ $existFriend = Db::table('tk_wechat_friend')
+ ->where('wechatAccountId', $targetWechatId)
+ ->where('wechatId', $friend['wechatId'])
+ ->where('isDeleted', 0)
+ ->find();
+
+ if ($existFriend) {
+ // 已经存在此好友,跳过
+ $duplicateCount++;
+ continue;
+ }
+
+ // 准备插入数据
+ $newFriend = [
+ 'wechatAccountId' => $targetWechatId,
+ 'alias' => $friend['alias'],
+ 'wechatId' => $friend['wechatId'],
+ 'conRemark' => $friend['conRemark'],
+ 'nickname' => $friend['nickname'],
+ 'pyInitial' => $friend['pyInitial'],
+ 'quanPin' => $friend['quanPin'],
+ 'avatar' => $friend['avatar'],
+ 'gender' => $friend['gender'],
+ 'region' => $friend['region'],
+ 'addFrom' => $friend['addFrom'],
+ 'labels' => $friend['labels'],
+ 'signature' => $friend['signature'],
+ 'isDeleted' => 0,
+ 'isPassed' => $friend['isPassed'],
+ 'accountId' => $friend['accountId'],
+ 'extendFields' => $friend['extendFields'],
+ 'accountUserName' => $friend['accountUserName'],
+ 'accountRealName' => $friend['accountRealName'],
+ 'accountNickname' => $friend['accountNickname'],
+ 'ownerAlias' => $targetWechat['alias'],
+ 'ownerWechatId' => $targetWechat['wechatId'],
+ 'ownerNickname' => $targetWechat['nickname'] ?: $targetWechat['accountNickname'],
+ 'ownerAvatar' => $targetWechat['avatar'],
+ 'phone' => $friend['phone'],
+ 'thirdParty' => $friend['thirdParty'],
+ 'groupId' => $friend['groupId'],
+ 'passTime' => $friend['passTime'],
+ 'additionalPicture' => $friend['additionalPicture'],
+ 'desc' => $friend['desc'],
+ 'country' => $friend['country'],
+ 'province' => $friend['province'],
+ 'city' => $friend['city'],
+ 'createTime' => date('Y-m-d H:i:s'),
+ 'updateTime' => date('Y-m-d H:i:s')
+ ];
+
+ // 插入新好友记录
+ $result = Db::table('tk_wechat_friend')->insert($newFriend);
+
+ if ($result) {
+ $successCount++;
+ } else {
+ $failCount++;
+ $failList[] = [
+ 'id' => $friend['id'],
+ 'wechatId' => $friend['wechatId'],
+ 'nickname' => $friend['nickname']
+ ];
+ }
+ }
+
+ // 更新两个微信账号的好友数量
+ $maleFriendsCount = Db::table('tk_wechat_friend')
+ ->where('wechatAccountId', $targetWechatId)
+ ->where('isDeleted', 0)
+ ->where('gender', 1)
+ ->count();
+
+ $femaleFriendsCount = Db::table('tk_wechat_friend')
+ ->where('wechatAccountId', $targetWechatId)
+ ->where('isDeleted', 0)
+ ->where('gender', 2)
+ ->count();
+
+ $totalFriendsCount = $maleFriendsCount + $femaleFriendsCount;
+
+ // 更新目标微信账号的好友数量
+ WechatAccount::where('id', $targetWechatId)
+ ->update([
+ 'totalFriend' => $totalFriendsCount,
+ 'maleFriend' => $maleFriendsCount,
+ 'femaleFriend' => $femaleFriendsCount,
+ 'updateTime' => date('Y-m-d H:i:s')
+ ]);
+
+ // 提交事务
+ Db::commit();
+
+ return json([
+ 'code' => 200,
+ 'msg' => '好友转移成功',
+ 'data' => [
+ 'total' => $totalFriends,
+ 'success' => $successCount,
+ 'fail' => $failCount,
+ 'duplicate' => $duplicateCount,
+ 'failList' => $failList
+ ]
+ ]);
+ } catch (\Exception $e) {
+ // 回滚事务
+ Db::rollback();
+ throw $e;
+ }
+ } catch (\Exception $e) {
+ return json([
+ 'code' => 500,
+ 'msg' => '好友转移失败:' . $e->getMessage()
+ ]);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Server/application/devices/model/WechatAccount.php b/Server/application/devices/model/WechatAccount.php
new file mode 100644
index 00000000..64fc8a64
--- /dev/null
+++ b/Server/application/devices/model/WechatAccount.php
@@ -0,0 +1,129 @@
+ 'integer',
+ 'deviceAccountId' => 'integer',
+ 'keFuAlive' => 'integer',
+ 'deviceAlive' => 'integer',
+ 'wechatAlive' => 'integer',
+ 'yesterdayMsgCount' => 'integer',
+ 'sevenDayMsgCount' => 'integer',
+ 'thirtyDayMsgCount' => 'integer',
+ 'totalFriend' => 'integer',
+ 'maleFriend' => 'integer',
+ 'femaleFriend' => 'integer',
+ 'gender' => 'integer',
+ 'currentDeviceId' => 'integer',
+ 'isDeleted' => 'integer',
+ 'groupId' => 'integer'
+ ];
+
+ /**
+ * 获取在线微信账号数量
+ *
+ * @param array $where 额外的查询条件
+ * @return int 微信账号数量
+ */
+ public static function getOnlineWechatCount($where = [])
+ {
+ $condition = [
+ 'deviceAlive' => 1,
+ 'wechatAlive' => 1,
+ 'isDeleted' => 0
+ ];
+
+ // 合并额外条件
+ if (!empty($where)) {
+ $condition = array_merge($condition, $where);
+ }
+
+ return self::where($condition)->count();
+ }
+
+ /**
+ * 获取有登录微信的设备数量
+ *
+ * @param array $where 额外的查询条件
+ * @return int 设备数量
+ */
+ public static function getDeviceWithWechatCount($where = [])
+ {
+ $condition = [
+ 'deviceAlive' => 1,
+ 'isDeleted' => 0
+ ];
+
+ // 合并额外条件
+ if (!empty($where)) {
+ $condition = array_merge($condition, $where);
+ }
+
+ return self::where($condition)->count();
+ }
+
+ /**
+ * 获取在线微信账号列表
+ *
+ * @param array $where 额外的查询条件
+ * @param string $order 排序方式
+ * @param int $page 页码
+ * @param int $limit 每页数量
+ * @return \think\Paginator 分页对象
+ */
+ public static function getOnlineWechatList($where = [], $order = 'id desc', $page = 1, $limit = 10)
+ {
+ $condition = [
+ 'wechatAlive' => 1,
+ 'deviceAlive' => 1,
+ 'isDeleted' => 0
+ ];
+
+ // 合并额外条件
+ if (!empty($where)) {
+ $condition = array_merge($condition, $where);
+ }
+
+ return self::where($condition)
+ ->field([
+ 'id',
+ 'wechatId',
+ 'accountNickname',
+ 'nickname',
+ 'accountUserName',
+ 'avatar',
+ 'wechatAlive',
+ 'deviceAlive',
+ 'totalFriend',
+ 'maleFriend',
+ 'femaleFriend',
+ 'imei',
+ 'deviceMemo',
+ 'yesterdayMsgCount'
+ ])
+ ->order($order)
+ ->paginate($limit, false, ['page' => $page]);
+ }
+}
\ No newline at end of file