diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml
new file mode 100644
index 0000000..a75b23a
--- /dev/null
+++ b/.gitea/workflows/deploy.yml
@@ -0,0 +1,54 @@
+name: 部署到群晖
+
+on:
+ push:
+ branches: [main, master]
+
+jobs:
+ deploy:
+ runs-on: ubuntu-latest
+ steps:
+ - name: 安装 Docker CLI
+ run: |
+ sed -i 's|deb.debian.org|mirrors.tuna.tsinghua.edu.cn|g' /etc/apt/sources.list /etc/apt/sources.list.d/*.list 2>/dev/null || true
+ sed -i 's|security.debian.org|mirrors.tuna.tsinghua.edu.cn/debian-security|g' /etc/apt/sources.list /etc/apt/sources.list.d/*.list 2>/dev/null || true
+ apt-get update -qq
+ apt-get install -y -qq docker.io
+
+ - name: 拉取代码
+ uses: actions/checkout@v4
+
+ - name: 构建镜像
+ run: docker build -t birthday-server:latest ./server
+
+ - name: 停止旧容器
+ run: |
+ docker stop birthday-server 2>/dev/null || true
+ docker rm birthday-server 2>/dev/null || true
+
+ - name: 准备持久化目录
+ run: mkdir -p /volume1/docker/apps/birthday-server/data
+
+ - name: 启动新容器
+ env:
+ WX_APPID: ${{ secrets.WX_APPID }}
+ WX_APPSECRET: ${{ secrets.WX_APPSECRET }}
+ WX_TEMPLATE_ID: ${{ secrets.WX_TEMPLATE_ID }}
+ WX_MINIPROGRAM_STATE: ${{ secrets.WX_MINIPROGRAM_STATE }}
+ REMINDER_CRON: ${{ secrets.REMINDER_CRON }}
+ run: |
+ docker run -d \
+ --name birthday-server \
+ --restart unless-stopped \
+ -p 15002:3000 \
+ -v /volume1/docker/apps/birthday-server/data:/app/data \
+ -e TZ=Asia/Shanghai \
+ -e WX_APPID="$WX_APPID" \
+ -e WX_APPSECRET="$WX_APPSECRET" \
+ -e WX_TEMPLATE_ID="${WX_TEMPLATE_ID:-6J7Stt-lu7DKU6jblJ0nZGq_D81z5glnksf7qWfy5Yw}" \
+ -e WX_MINIPROGRAM_STATE="${WX_MINIPROGRAM_STATE:-formal}" \
+ -e REMINDER_CRON="${REMINDER_CRON:-0 9 * * *}" \
+ birthday-server:latest
+
+ - name: 部署完成提示
+ run: echo "部署完成,访问 http://192.168.1.66:15002/api/health"
diff --git a/.gitignore b/.gitignore
index 14ea590..6aaa899 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,3 +12,8 @@ $RECYCLE.BIN/
# Node.js
node_modules/
+
+# 后端运行时数据 & 敏感配置
+server/.env
+server/data/
+server/node_modules/
diff --git a/app.js b/app.js
index c0460e7..5639c17 100644
--- a/app.js
+++ b/app.js
@@ -1,27 +1,44 @@
+const api = require('./utils/api')
+
App({
onLaunch() {
- // 展示本地存储能力
const logs = wx.getStorageSync('logs') || []
logs.unshift(Date.now())
wx.setStorageSync('logs', logs)
- // 初始化数据
this.initData()
+ this.getUserOpenId()
},
- // 初始化数据结构
initData() {
- // 检查是否有旧数据
const persons = wx.getStorageSync('persons') || []
const anniversaries = wx.getStorageSync('anniversaries') || []
-
if (persons.length === 0 && anniversaries.length === 0) {
console.log('初始化数据结构')
}
},
+ // 获取 openid:调自建后端 /api/login
+ async getUserOpenId() {
+ // 已缓存就直接复用,避免每次启动都登录
+ const cached = wx.getStorageSync('openid')
+ if (cached) {
+ this.globalData.openid = cached
+ return
+ }
+ try {
+ const res = await api.login()
+ this.globalData.openid = res.openid
+ wx.setStorageSync('openid', res.openid)
+ console.log('获取openid成功:', res.openid)
+ } catch (err) {
+ console.error('获取openid失败:', err)
+ }
+ },
+
globalData: {
- userInfo: null
+ userInfo: null,
+ openid: ''
}
})
diff --git a/app.json b/app.json
index e8333a6..6bba91c 100644
--- a/app.json
+++ b/app.json
@@ -16,27 +16,21 @@
},
"tabBar": {
"color": "#7A7E83",
- "selectedColor": "#3cc51f",
+ "selectedColor": "#07c160",
"borderStyle": "black",
"backgroundColor": "#ffffff",
"list": [
{
"pagePath": "pages/index/index",
- "iconPath": "/images/home.png",
- "selectedIconPath": "/images/home-active.png",
- "text": "首页"
+ "text": "🏠 首页"
},
{
"pagePath": "pages/calendar/calendar",
- "iconPath": "/images/calendar.png",
- "selectedIconPath": "/images/calendar-active.png",
- "text": "日历"
+ "text": "📅 日历"
},
{
"pagePath": "pages/settings/settings",
- "iconPath": "/images/settings.png",
- "selectedIconPath": "/images/settings-active.png",
- "text": "设置"
+ "text": "⚙️ 设置"
}
]
},
diff --git a/app.wxss b/app.wxss
index be0934b..2f03401 100644
--- a/app.wxss
+++ b/app.wxss
@@ -11,7 +11,8 @@
/* 全局样式 */
page {
- background-color: #f5f5f5;
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+ background-attachment: fixed;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB',
'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
@@ -23,44 +24,53 @@ page {
/* 按钮样式 */
.btn {
- border-radius: 8rpx;
+ border-radius: 12rpx;
font-size: 32rpx;
padding: 24rpx 48rpx;
+ transition: all 0.3s ease;
}
.btn-primary {
- background-color: #07c160;
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: #fff;
+ box-shadow: 0 4rpx 16rpx rgba(102, 126, 234, 0.4);
}
.btn-secondary {
background-color: #fff;
color: #333;
- border: 1px solid #ddd;
+ border: 2rpx solid #e8e8e8;
}
/* 卡片样式 */
.card {
background-color: #fff;
- border-radius: 16rpx;
+ border-radius: 24rpx;
padding: 32rpx;
margin-bottom: 24rpx;
- box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08);
+ box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.12);
+ transition: all 0.3s ease;
}
/* 输入框样式 */
.input {
- background-color: #fff;
+ background-color: #f8f9fa;
padding: 24rpx;
- border-radius: 8rpx;
- border: 1px solid #e0e0e0;
+ border-radius: 12rpx;
+ border: 2rpx solid transparent;
font-size: 28rpx;
+ transition: all 0.3s ease;
+}
+
+.input:focus {
+ background-color: #fff;
+ border-color: #667eea;
}
/* 分割线 */
.divider {
height: 1rpx;
- background-color: #f0f0f0;
+ background: linear-gradient(90deg, transparent, #e0e0e0, transparent);
margin: 32rpx 0;
}
@@ -68,17 +78,20 @@ page {
.empty-state {
text-align: center;
padding: 120rpx 40rpx;
- color: #999;
+ color: rgba(255, 255, 255, 0.8);
}
.empty-state .icon {
- font-size: 120rpx;
+ font-size: 140rpx;
margin-bottom: 32rpx;
+ filter: drop-shadow(0 4rpx 8rpx rgba(0, 0, 0, 0.1));
}
.empty-state .text {
- font-size: 28rpx;
- color: #999;
+ font-size: 32rpx;
+ color: rgba(255, 255, 255, 0.9);
+ font-weight: 500;
+ margin-bottom: 12rpx;
}
/* 浮动按钮 */
@@ -86,16 +99,22 @@ page {
position: fixed;
bottom: 120rpx;
right: 40rpx;
- width: 100rpx;
- height: 100rpx;
+ width: 112rpx;
+ height: 112rpx;
border-radius: 50%;
- background-color: #07c160;
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: #fff;
display: flex;
align-items: center;
justify-content: center;
- font-size: 60rpx;
- box-shadow: 0 8rpx 24rpx rgba(7, 193, 96, 0.3);
+ font-size: 64rpx;
+ box-shadow: 0 12rpx 40rpx rgba(102, 126, 234, 0.5);
z-index: 100;
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.fab:active {
+ transform: scale(0.92);
+ box-shadow: 0 8rpx 24rpx rgba(102, 126, 234, 0.4);
}
diff --git a/cloudfunctions/login/config.json b/cloudfunctions/login/config.json
new file mode 100644
index 0000000..eaa6dae
--- /dev/null
+++ b/cloudfunctions/login/config.json
@@ -0,0 +1,6 @@
+{
+ "permissions": {
+ "openapi": []
+ }
+}
+
diff --git a/cloudfunctions/login/index.js b/cloudfunctions/login/index.js
new file mode 100644
index 0000000..db6e5c9
--- /dev/null
+++ b/cloudfunctions/login/index.js
@@ -0,0 +1,18 @@
+// 云函数:获取用户openid
+const cloud = require('wx-server-sdk')
+
+cloud.init({
+ env: cloud.DYNAMIC_CURRENT_ENV
+})
+
+exports.main = async (event, context) => {
+ const wxContext = cloud.getWXContext()
+
+ return {
+ openid: wxContext.OPENID,
+ appid: wxContext.APPID,
+ unionid: wxContext.UNIONID,
+ env: wxContext.ENV
+ }
+}
+
diff --git a/cloudfunctions/login/package.json b/cloudfunctions/login/package.json
new file mode 100644
index 0000000..f9ccc6a
--- /dev/null
+++ b/cloudfunctions/login/package.json
@@ -0,0 +1,10 @@
+{
+ "name": "login",
+ "version": "1.0.0",
+ "description": "获取用户openid",
+ "main": "index.js",
+ "dependencies": {
+ "wx-server-sdk": "~2.6.3"
+ }
+}
+
diff --git a/cloudfunctions/sendReminder/config.json b/cloudfunctions/sendReminder/config.json
new file mode 100644
index 0000000..a2e4b8a
--- /dev/null
+++ b/cloudfunctions/sendReminder/config.json
@@ -0,0 +1,15 @@
+{
+ "permissions": {
+ "openapi": [
+ "subscribeMessage.send"
+ ]
+ },
+ "triggers": [
+ {
+ "name": "dailyReminder",
+ "type": "timer",
+ "config": "0 0 9 * * * *"
+ }
+ ]
+}
+
diff --git a/cloudfunctions/sendReminder/index.js b/cloudfunctions/sendReminder/index.js
new file mode 100644
index 0000000..44685ca
--- /dev/null
+++ b/cloudfunctions/sendReminder/index.js
@@ -0,0 +1,197 @@
+// 云函数:发送生日提醒
+const cloud = require('wx-server-sdk')
+
+cloud.init({
+ env: cloud.DYNAMIC_CURRENT_ENV
+})
+
+const db = cloud.database()
+
+// 模板ID
+const TEMPLATE_ID = '6J7Stt-lu7DKU6jblJ0nZGq_D81z5glnksf7qWfy5Yw'
+
+/**
+ * 计算两个日期之间的天数差
+ */
+function getDaysUntil(targetDate) {
+ const today = new Date()
+ today.setHours(0, 0, 0, 0)
+
+ const target = new Date(targetDate)
+ target.setHours(0, 0, 0, 0)
+
+ const diffTime = target - today
+ const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24))
+
+ return diffDays
+}
+
+/**
+ * 格式化日期
+ */
+function formatDate(date) {
+ const d = new Date(date)
+ const year = d.getFullYear()
+ const month = String(d.getMonth() + 1).padStart(2, '0')
+ const day = String(d.getDate()).padStart(2, '0')
+ return `${year}年${month}月${day}日`
+}
+
+const TYPE_NAMES = {
+ birthday: '公历生日',
+ lunar_birthday: '农历生日',
+ wedding: '结婚纪念日',
+ engagement: '订婚纪念日',
+ other: '其他纪念日'
+}
+
+/**
+ * 获取类型名称
+ */
+function getTypeName(type, customName) {
+ if (type === 'other' && customName) return customName
+ return TYPE_NAMES[type] || '纪念日'
+}
+
+/**
+ * 获取今年的纪念日日期
+ */
+function getThisYearDate(anniversary) {
+ const today = new Date()
+ const currentYear = today.getFullYear()
+
+ // 使用公历日期计算
+ let thisYearDate = new Date(currentYear, anniversary.solarMonth - 1, anniversary.solarDay)
+
+ // 如果今年的已经过了,计算明年的
+ const daysUntil = getDaysUntil(thisYearDate)
+ if (daysUntil < 0) {
+ thisYearDate = new Date(currentYear + 1, anniversary.solarMonth - 1, anniversary.solarDay)
+ }
+
+ return thisYearDate
+}
+
+/**
+ * 主函数
+ */
+exports.main = async (event, context) => {
+ console.log('开始执行提醒任务...')
+
+ try {
+ // 获取所有启用提醒的纪念日
+ const anniversariesRes = await db.collection('anniversaries')
+ .where({
+ remindEnabled: true
+ })
+ .get()
+
+ console.log(`找到 ${anniversariesRes.data.length} 条启用提醒的纪念日`)
+
+ let successCount = 0
+ let failCount = 0
+
+ // 遍历每个纪念日
+ for (const anniversary of anniversariesRes.data) {
+ try {
+ // 计算今年的纪念日日期
+ const thisYearDate = getThisYearDate(anniversary)
+ const daysUntil = getDaysUntil(thisYearDate)
+
+ console.log(`${anniversary.personName} 的 ${getTypeName(anniversary.type, anniversary.customTypeName)},还有 ${daysUntil} 天`)
+
+ // 判断是否需要提醒
+ const shouldRemind = (
+ daysUntil === 0 || // 当天
+ daysUntil === anniversary.remindDays // 提前N天
+ )
+
+ if (shouldRemind) {
+ // 检查今天是否已经发送过提醒
+ const today = new Date()
+ today.setHours(0, 0, 0, 0)
+
+ const logRes = await db.collection('remind_logs')
+ .where({
+ anniversaryId: anniversary._id,
+ sendDate: db.command.gte(today)
+ })
+ .count()
+
+ if (logRes.total > 0) {
+ console.log(`今天已发送过提醒,跳过: ${anniversary.personName}`)
+ continue
+ }
+
+ // 发送订阅消息
+ const sendRes = await cloud.openapi.subscribeMessage.send({
+ touser: anniversary.openid,
+ page: 'pages/index/index',
+ data: {
+ name1: {
+ value: anniversary.personName
+ },
+ thing2: {
+ value: daysUntil === 0 ? '今天' : `还有${daysUntil}天`
+ },
+ thing6: {
+ value: formatDate(thisYearDate)
+ },
+ thing5: {
+ value: anniversary.remark || '别忘了准备一份礼物哦!'
+ }
+ },
+ templateId: TEMPLATE_ID,
+ miniprogramState: 'formal' // 正式版
+ })
+
+ console.log(`发送成功: ${anniversary.personName}`, sendRes)
+
+ // 记录提醒日志
+ await db.collection('remind_logs').add({
+ data: {
+ anniversaryId: anniversary._id,
+ personName: anniversary.personName,
+ typeName: getTypeName(anniversary.type, anniversary.customTypeName),
+ daysUntil: daysUntil,
+ sendDate: new Date(),
+ status: 'success'
+ }
+ })
+
+ successCount++
+ }
+ } catch (err) {
+ console.error(`发送失败: ${anniversary.personName}`, err)
+ failCount++
+
+ // 记录失败日志
+ await db.collection('remind_logs').add({
+ data: {
+ anniversaryId: anniversary._id,
+ personName: anniversary.personName,
+ sendDate: new Date(),
+ status: 'failed',
+ error: err.message
+ }
+ })
+ }
+ }
+
+ console.log(`提醒任务完成: 成功${successCount}条,失败${failCount}条`)
+
+ return {
+ success: true,
+ total: anniversariesRes.data.length,
+ successCount,
+ failCount
+ }
+ } catch (err) {
+ console.error('提醒任务执行失败:', err)
+ return {
+ success: false,
+ error: err.message
+ }
+ }
+}
+
diff --git a/cloudfunctions/sendReminder/package-lock.json b/cloudfunctions/sendReminder/package-lock.json
new file mode 100644
index 0000000..17818f7
--- /dev/null
+++ b/cloudfunctions/sendReminder/package-lock.json
@@ -0,0 +1,1525 @@
+{
+ "name": "sendReminder",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "sendReminder",
+ "version": "1.0.0",
+ "dependencies": {
+ "wx-server-sdk": "~2.6.3"
+ }
+ },
+ "node_modules/@cloudbase/database": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/@cloudbase/database/-/database-1.4.1.tgz",
+ "integrity": "sha512-BYLXHS6c+WhxAvvdak8Z3W+heScqBBPu/CQ76gC8v1Scuy5qf4qxuPWNzyoxde/eZsmc+BRRCFyIq4xUnIot8g==",
+ "license": "ISC",
+ "dependencies": {
+ "bson": "^4.0.3",
+ "lodash.clonedeep": "4.5.0",
+ "lodash.set": "4.3.2",
+ "lodash.unset": "4.5.2"
+ }
+ },
+ "node_modules/@cloudbase/node-sdk": {
+ "version": "2.9.1",
+ "resolved": "https://registry.npmjs.org/@cloudbase/node-sdk/-/node-sdk-2.9.1.tgz",
+ "integrity": "sha512-4JGLiy9/Ko7d1pnBgq5mtIUm5v9ig1tHqAeLrkMc8b4vVBRTnYlxJer3uKXq6+9fjLprxNyRSahEg4QR8/Gbkw==",
+ "license": "MIT",
+ "dependencies": {
+ "@cloudbase/database": "1.4.1",
+ "@cloudbase/signature-nodejs": "1.0.0-beta.0",
+ "@types/retry": "^0.12.0",
+ "agentkeepalive": "^4.1.3",
+ "axios": "^0.21.1",
+ "is-regex": "^1.0.4",
+ "jsonwebtoken": "^8.5.1",
+ "lodash.merge": "^4.6.1",
+ "request": "^2.87.0",
+ "request-promise": "^4.2.5",
+ "retry": "^0.12.0",
+ "ts-node": "^8.10.2",
+ "xml2js": "^0.4.19"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/@cloudbase/signature-nodejs": {
+ "version": "1.0.0-beta.0",
+ "resolved": "https://registry.npmjs.org/@cloudbase/signature-nodejs/-/signature-nodejs-1.0.0-beta.0.tgz",
+ "integrity": "sha512-gpKqwsVk/D2PzvFamYNReymXSdvRSY90eZ1ARf+1wZ8oT6OpK9kr6nmevGykMxN1n17Gn92hBbWqAxU9o3+kAQ==",
+ "dependencies": {
+ "@types/clone": "^0.1.30",
+ "clone": "^2.1.2",
+ "is-stream": "^2.0.0",
+ "url": "^0.11.0"
+ }
+ },
+ "node_modules/@protobufjs/aspromise": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
+ "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@protobufjs/base64": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
+ "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@protobufjs/codegen": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
+ "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@protobufjs/eventemitter": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
+ "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@protobufjs/fetch": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
+ "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@protobufjs/aspromise": "^1.1.1",
+ "@protobufjs/inquire": "^1.1.0"
+ }
+ },
+ "node_modules/@protobufjs/float": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
+ "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@protobufjs/inquire": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
+ "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@protobufjs/path": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
+ "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@protobufjs/pool": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
+ "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@protobufjs/utf8": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
+ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@types/clone": {
+ "version": "0.1.30",
+ "resolved": "https://registry.npmjs.org/@types/clone/-/clone-0.1.30.tgz",
+ "integrity": "sha512-vcxBr+ybljeSiasmdke1cQ9ICxoEwaBgM1OQ/P5h4MPj/kRyLcDl5L8PrftlbyV1kBbJIs3M3x1A1+rcWd4mEA==",
+ "license": "MIT"
+ },
+ "node_modules/@types/long": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz",
+ "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==",
+ "license": "MIT"
+ },
+ "node_modules/@types/node": {
+ "version": "24.9.1",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.1.tgz",
+ "integrity": "sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==",
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~7.16.0"
+ }
+ },
+ "node_modules/@types/retry": {
+ "version": "0.12.5",
+ "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.5.tgz",
+ "integrity": "sha512-3xSjTp3v03X/lSQLkczaN9UIEwJMoMCA1+Nb5HfbJEQWogdeQIyVtTvxPXDQjZ5zws8rFQfVfRdz03ARihPJgw==",
+ "license": "MIT"
+ },
+ "node_modules/agentkeepalive": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz",
+ "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==",
+ "license": "MIT",
+ "dependencies": {
+ "humanize-ms": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 8.0.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==",
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/arg": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+ "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
+ "license": "MIT"
+ },
+ "node_modules/asn1": {
+ "version": "0.2.6",
+ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
+ "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": "~2.1.0"
+ }
+ },
+ "node_modules/assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
+ "license": "MIT"
+ },
+ "node_modules/aws-sign2": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
+ "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/aws4": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz",
+ "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==",
+ "license": "MIT"
+ },
+ "node_modules/axios": {
+ "version": "0.21.4",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
+ "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
+ "license": "MIT",
+ "dependencies": {
+ "follow-redirects": "^1.14.0"
+ }
+ },
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/bcrypt-pbkdf": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
+ "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "tweetnacl": "^0.14.3"
+ }
+ },
+ "node_modules/bignumber.js": {
+ "version": "9.3.1",
+ "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz",
+ "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==",
+ "license": "MIT",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/bluebird": {
+ "version": "3.7.2",
+ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
+ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
+ "license": "MIT"
+ },
+ "node_modules/bson": {
+ "version": "4.7.2",
+ "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.2.tgz",
+ "integrity": "sha512-Ry9wCtIZ5kGqkJoi6aD8KjxFZEx78guTQDnpXWiNthsxzrxAK/i8E6pCHAIZTbaEFWcOCvbecMukfK7XUvyLpQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "buffer": "^5.6.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/buffer": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+ "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
+ }
+ },
+ "node_modules/buffer-equal-constant-time": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+ "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
+ "license": "BSD-3-Clause"
+ },
+ "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==",
+ "license": "MIT"
+ },
+ "node_modules/call-bind-apply-helpers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+ "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/call-bound": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
+ "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "get-intrinsic": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/caseless": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+ "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/clone": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
+ "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "license": "MIT",
+ "dependencies": {
+ "delayed-stream": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==",
+ "license": "MIT"
+ },
+ "node_modules/dashdash": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+ "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==",
+ "license": "MIT",
+ "dependencies": {
+ "assert-plus": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/diff": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+ "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
+ "node_modules/dunder-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+ "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/ecc-jsbn": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
+ "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==",
+ "license": "MIT",
+ "dependencies": {
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.1.0"
+ }
+ },
+ "node_modules/ecdsa-sig-formatter": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
+ "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/es-define-property": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-object-atoms": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
+ "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+ "license": "MIT"
+ },
+ "node_modules/extsprintf": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+ "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==",
+ "engines": [
+ "node >=0.6.0"
+ ],
+ "license": "MIT"
+ },
+ "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==",
+ "license": "MIT"
+ },
+ "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==",
+ "license": "MIT"
+ },
+ "node_modules/follow-redirects": {
+ "version": "1.15.11",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
+ "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/RubenVerborgh"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=4.0"
+ },
+ "peerDependenciesMeta": {
+ "debug": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/forever-agent": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+ "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/form-data": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
+ "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
+ "license": "MIT",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.6",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 0.12"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "es-define-property": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
+ "function-bind": "^1.1.2",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "hasown": "^2.0.2",
+ "math-intrinsics": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+ "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+ "license": "MIT",
+ "dependencies": {
+ "dunder-proto": "^1.0.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/getpass": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+ "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==",
+ "license": "MIT",
+ "dependencies": {
+ "assert-plus": "^1.0.0"
+ }
+ },
+ "node_modules/gopd": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/har-schema": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
+ "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/har-validator": {
+ "version": "5.1.5",
+ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
+ "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
+ "deprecated": "this library is no longer supported",
+ "license": "MIT",
+ "dependencies": {
+ "ajv": "^6.12.3",
+ "har-schema": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+ "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-tostringtag": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+ "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+ "license": "MIT",
+ "dependencies": {
+ "has-symbols": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/http-signature": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
+ "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==",
+ "license": "MIT",
+ "dependencies": {
+ "assert-plus": "^1.0.0",
+ "jsprim": "^1.2.2",
+ "sshpk": "^1.7.0"
+ },
+ "engines": {
+ "node": ">=0.8",
+ "npm": ">=1.3.7"
+ }
+ },
+ "node_modules/humanize-ms": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
+ "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.0.0"
+ }
+ },
+ "node_modules/ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/is-regex": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
+ "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "gopd": "^1.2.0",
+ "has-tostringtag": "^1.0.2",
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-stream": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-typedarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==",
+ "license": "MIT"
+ },
+ "node_modules/isstream": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+ "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==",
+ "license": "MIT"
+ },
+ "node_modules/jsbn": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+ "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==",
+ "license": "MIT"
+ },
+ "node_modules/json-bigint": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz",
+ "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==",
+ "license": "MIT",
+ "dependencies": {
+ "bignumber.js": "^9.0.0"
+ }
+ },
+ "node_modules/json-schema": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
+ "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==",
+ "license": "(AFL-2.1 OR BSD-3-Clause)"
+ },
+ "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==",
+ "license": "MIT"
+ },
+ "node_modules/json-stringify-safe": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+ "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==",
+ "license": "ISC"
+ },
+ "node_modules/jsonwebtoken": {
+ "version": "8.5.1",
+ "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
+ "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==",
+ "license": "MIT",
+ "dependencies": {
+ "jws": "^3.2.2",
+ "lodash.includes": "^4.3.0",
+ "lodash.isboolean": "^3.0.3",
+ "lodash.isinteger": "^4.0.4",
+ "lodash.isnumber": "^3.0.3",
+ "lodash.isplainobject": "^4.0.6",
+ "lodash.isstring": "^4.0.1",
+ "lodash.once": "^4.0.0",
+ "ms": "^2.1.1",
+ "semver": "^5.6.0"
+ },
+ "engines": {
+ "node": ">=4",
+ "npm": ">=1.4.28"
+ }
+ },
+ "node_modules/jsprim": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
+ "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==",
+ "license": "MIT",
+ "dependencies": {
+ "assert-plus": "1.0.0",
+ "extsprintf": "1.3.0",
+ "json-schema": "0.4.0",
+ "verror": "1.10.0"
+ },
+ "engines": {
+ "node": ">=0.6.0"
+ }
+ },
+ "node_modules/jwa": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz",
+ "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==",
+ "license": "MIT",
+ "dependencies": {
+ "buffer-equal-constant-time": "^1.0.1",
+ "ecdsa-sig-formatter": "1.0.11",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/jws": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
+ "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
+ "license": "MIT",
+ "dependencies": {
+ "jwa": "^1.4.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.clonedeep": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
+ "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.includes": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
+ "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.isboolean": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
+ "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.isinteger": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
+ "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.isnumber": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
+ "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.isplainobject": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+ "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.isstring": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
+ "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.merge": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.once": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+ "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.set": {
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz",
+ "integrity": "sha512-4hNPN5jlm/N/HLMCO43v8BXKq9Z7QdAGc/VGrRD61w8gN9g/6jF9A4L1pbUgBLCffi0w9VsXfTOij5x8iTyFvg==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.unset": {
+ "version": "4.5.2",
+ "resolved": "https://registry.npmjs.org/lodash.unset/-/lodash.unset-4.5.2.tgz",
+ "integrity": "sha512-bwKX88k2JhCV9D1vtE8+naDKlLiGrSmf8zi/Y9ivFHwbmRfA8RxS/aVJ+sIht2XOwqoNr4xUPUkGZpc1sHFEKg==",
+ "license": "MIT"
+ },
+ "node_modules/long": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
+ "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/make-error": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+ "license": "ISC"
+ },
+ "node_modules/math-intrinsics": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+ "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "license": "MIT"
+ },
+ "node_modules/oauth-sign": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
+ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.13.4",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
+ "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/performance-now": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+ "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==",
+ "license": "MIT"
+ },
+ "node_modules/protobufjs": {
+ "version": "6.11.4",
+ "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz",
+ "integrity": "sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==",
+ "hasInstallScript": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@protobufjs/aspromise": "^1.1.2",
+ "@protobufjs/base64": "^1.1.2",
+ "@protobufjs/codegen": "^2.0.4",
+ "@protobufjs/eventemitter": "^1.1.0",
+ "@protobufjs/fetch": "^1.1.0",
+ "@protobufjs/float": "^1.0.2",
+ "@protobufjs/inquire": "^1.1.0",
+ "@protobufjs/path": "^1.1.2",
+ "@protobufjs/pool": "^1.1.0",
+ "@protobufjs/utf8": "^1.1.0",
+ "@types/long": "^4.0.1",
+ "@types/node": ">=13.7.0",
+ "long": "^4.0.0"
+ },
+ "bin": {
+ "pbjs": "bin/pbjs",
+ "pbts": "bin/pbts"
+ }
+ },
+ "node_modules/psl": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz",
+ "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==",
+ "license": "MIT",
+ "dependencies": {
+ "punycode": "^2.3.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/lupomontero"
+ }
+ },
+ "node_modules/punycode": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/qs": {
+ "version": "6.5.3",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz",
+ "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/request": {
+ "version": "2.88.2",
+ "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
+ "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
+ "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "aws-sign2": "~0.7.0",
+ "aws4": "^1.8.0",
+ "caseless": "~0.12.0",
+ "combined-stream": "~1.0.6",
+ "extend": "~3.0.2",
+ "forever-agent": "~0.6.1",
+ "form-data": "~2.3.2",
+ "har-validator": "~5.1.3",
+ "http-signature": "~1.2.0",
+ "is-typedarray": "~1.0.0",
+ "isstream": "~0.1.2",
+ "json-stringify-safe": "~5.0.1",
+ "mime-types": "~2.1.19",
+ "oauth-sign": "~0.9.0",
+ "performance-now": "^2.1.0",
+ "qs": "~6.5.2",
+ "safe-buffer": "^5.1.2",
+ "tough-cookie": "~2.5.0",
+ "tunnel-agent": "^0.6.0",
+ "uuid": "^3.3.2"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/request-promise": {
+ "version": "4.2.6",
+ "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.6.tgz",
+ "integrity": "sha512-HCHI3DJJUakkOr8fNoCc73E5nU5bqITjOYFMDrKHYOXWXrgD/SBaC7LjwuPymUprRyuF06UK7hd/lMHkmUXglQ==",
+ "deprecated": "request-promise has been deprecated because it extends the now deprecated request package, see https://github.com/request/request/issues/3142",
+ "license": "ISC",
+ "dependencies": {
+ "bluebird": "^3.5.0",
+ "request-promise-core": "1.1.4",
+ "stealthy-require": "^1.1.1",
+ "tough-cookie": "^2.3.3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ },
+ "peerDependencies": {
+ "request": "^2.34"
+ }
+ },
+ "node_modules/request-promise-core": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz",
+ "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==",
+ "license": "ISC",
+ "dependencies": {
+ "lodash": "^4.17.19"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ },
+ "peerDependencies": {
+ "request": "^2.34"
+ }
+ },
+ "node_modules/retry": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
+ "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "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==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "license": "MIT"
+ },
+ "node_modules/sax": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
+ "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==",
+ "license": "ISC"
+ },
+ "node_modules/semver": {
+ "version": "5.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
+ "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver"
+ }
+ },
+ "node_modules/side-channel": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
+ "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.3",
+ "side-channel-list": "^1.0.0",
+ "side-channel-map": "^1.0.1",
+ "side-channel-weakmap": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-list": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
+ "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-map": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
+ "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-weakmap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
+ "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3",
+ "side-channel-map": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "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==",
+ "license": "BSD-3-Clause",
+ "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==",
+ "license": "MIT",
+ "dependencies": {
+ "buffer-from": "^1.0.0",
+ "source-map": "^0.6.0"
+ }
+ },
+ "node_modules/sshpk": {
+ "version": "1.18.0",
+ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz",
+ "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==",
+ "license": "MIT",
+ "dependencies": {
+ "asn1": "~0.2.3",
+ "assert-plus": "^1.0.0",
+ "bcrypt-pbkdf": "^1.0.0",
+ "dashdash": "^1.12.0",
+ "ecc-jsbn": "~0.1.1",
+ "getpass": "^0.1.1",
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.0.2",
+ "tweetnacl": "~0.14.0"
+ },
+ "bin": {
+ "sshpk-conv": "bin/sshpk-conv",
+ "sshpk-sign": "bin/sshpk-sign",
+ "sshpk-verify": "bin/sshpk-verify"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/stealthy-require": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
+ "integrity": "sha512-ZnWpYnYugiOVEY5GkcuJK1io5V8QmNYChG62gSit9pQVGErXtrKuPC55ITaVSukmMta5qpMU7vqLt2Lnni4f/g==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/tcb-admin-node": {
+ "version": "1.23.0",
+ "resolved": "https://registry.npmjs.org/tcb-admin-node/-/tcb-admin-node-1.23.0.tgz",
+ "integrity": "sha512-SAbjTqMsSi63SId1BJ4kWdyGJzhxh9Tjvy3YXxcsoaAC2PtASn4UIYsBsiNEUfcn58QEn2tdvCvvf69WLLjjrg==",
+ "license": "MIT",
+ "dependencies": {
+ "@cloudbase/database": "0.9.15",
+ "@cloudbase/signature-nodejs": "^1.0.0-beta.0",
+ "is-regex": "^1.0.4",
+ "jsonwebtoken": "^8.5.1",
+ "lodash.merge": "^4.6.1",
+ "request": "^2.87.0",
+ "xml2js": "^0.4.19"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/tcb-admin-node/node_modules/@cloudbase/database": {
+ "version": "0.9.15",
+ "resolved": "https://registry.npmjs.org/@cloudbase/database/-/database-0.9.15.tgz",
+ "integrity": "sha512-63e7iIl+van41B39Tw4ScNe9TRCt+5GHjc7q6i8NzkWBLC3U3KlbWo79YHsUHUPI79POpQ8UMlMVo7HXIAO3dg==",
+ "license": "ISC",
+ "dependencies": {
+ "bson": "^4.0.2",
+ "lodash.clonedeep": "4.5.0",
+ "lodash.set": "4.3.2",
+ "lodash.unset": "4.5.2"
+ }
+ },
+ "node_modules/tough-cookie": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
+ "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "psl": "^1.1.28",
+ "punycode": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/ts-node": {
+ "version": "8.10.2",
+ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.10.2.tgz",
+ "integrity": "sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA==",
+ "license": "MIT",
+ "dependencies": {
+ "arg": "^4.1.0",
+ "diff": "^4.0.1",
+ "make-error": "^1.1.1",
+ "source-map-support": "^0.5.17",
+ "yn": "3.1.1"
+ },
+ "bin": {
+ "ts-node": "dist/bin.js",
+ "ts-node-script": "dist/bin-script.js",
+ "ts-node-transpile-only": "dist/bin-transpile.js",
+ "ts-script": "dist/bin-script-deprecated.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ },
+ "peerDependencies": {
+ "typescript": ">=2.7"
+ }
+ },
+ "node_modules/tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+ "license": "0BSD"
+ },
+ "node_modules/tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/tweetnacl": {
+ "version": "0.14.5",
+ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+ "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==",
+ "license": "Unlicense"
+ },
+ "node_modules/typescript": {
+ "version": "5.9.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "7.16.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
+ "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
+ "license": "MIT"
+ },
+ "node_modules/uri-js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/url": {
+ "version": "0.11.4",
+ "resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz",
+ "integrity": "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==",
+ "license": "MIT",
+ "dependencies": {
+ "punycode": "^1.4.1",
+ "qs": "^6.12.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/url/node_modules/punycode": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+ "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==",
+ "license": "MIT"
+ },
+ "node_modules/url/node_modules/qs": {
+ "version": "6.14.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
+ "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "side-channel": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/uuid": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
+ "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
+ "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
+ "license": "MIT",
+ "bin": {
+ "uuid": "bin/uuid"
+ }
+ },
+ "node_modules/verror": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+ "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==",
+ "engines": [
+ "node >=0.6.0"
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "assert-plus": "^1.0.0",
+ "core-util-is": "1.0.2",
+ "extsprintf": "^1.2.0"
+ }
+ },
+ "node_modules/wx-server-sdk": {
+ "version": "2.6.3",
+ "resolved": "https://registry.npmjs.org/wx-server-sdk/-/wx-server-sdk-2.6.3.tgz",
+ "integrity": "sha512-wCSAO94HScMVnalb4WVbOqjTyKxus4/jPYV41ct9liHXv/hGGlDqUWV1vb1icyQKXp+mSslvpBNNjYnZAM5MVA==",
+ "license": "MIT",
+ "dependencies": {
+ "@cloudbase/node-sdk": "2.9.1",
+ "json-bigint": "^1.0.0",
+ "protobufjs": "^6.8.8",
+ "tcb-admin-node": "latest",
+ "tslib": "^1.9.3"
+ }
+ },
+ "node_modules/xml2js": {
+ "version": "0.4.23",
+ "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
+ "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
+ "license": "MIT",
+ "dependencies": {
+ "sax": ">=0.6.0",
+ "xmlbuilder": "~11.0.0"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/xmlbuilder": {
+ "version": "11.0.1",
+ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
+ "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/yn": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
+ "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ }
+ }
+}
diff --git a/cloudfunctions/sendReminder/package.json b/cloudfunctions/sendReminder/package.json
new file mode 100644
index 0000000..ff03a47
--- /dev/null
+++ b/cloudfunctions/sendReminder/package.json
@@ -0,0 +1,10 @@
+{
+ "name": "sendReminder",
+ "version": "1.0.0",
+ "description": "发送生日提醒订阅消息",
+ "main": "index.js",
+ "dependencies": {
+ "wx-server-sdk": "~2.6.3"
+ }
+}
+
diff --git a/cloudfunctions/syncAnniversary/config.json b/cloudfunctions/syncAnniversary/config.json
new file mode 100644
index 0000000..eaa6dae
--- /dev/null
+++ b/cloudfunctions/syncAnniversary/config.json
@@ -0,0 +1,6 @@
+{
+ "permissions": {
+ "openapi": []
+ }
+}
+
diff --git a/cloudfunctions/syncAnniversary/index.js b/cloudfunctions/syncAnniversary/index.js
new file mode 100644
index 0000000..6b8591e
--- /dev/null
+++ b/cloudfunctions/syncAnniversary/index.js
@@ -0,0 +1,157 @@
+// 云函数:同步纪念日数据到云端
+const cloud = require('wx-server-sdk')
+
+cloud.init({
+ env: cloud.DYNAMIC_CURRENT_ENV
+})
+
+const db = cloud.database()
+
+exports.main = async (event, context) => {
+ const wxContext = cloud.getWXContext()
+ const openid = wxContext.OPENID
+
+ const { action, data } = event
+
+ try {
+ switch (action) {
+ case 'add':
+ // 添加纪念日
+ return await addAnniversary(openid, data)
+
+ case 'update':
+ // 更新纪念日
+ return await updateAnniversary(openid, data)
+
+ case 'delete':
+ // 删除纪念日
+ return await deleteAnniversary(openid, data.id)
+
+ case 'sync':
+ // 批量同步
+ return await syncAnniversaries(openid, data)
+
+ case 'get':
+ // 获取用户所有纪念日
+ return await getAnniversaries(openid)
+
+ default:
+ return {
+ success: false,
+ error: '未知操作'
+ }
+ }
+ } catch (err) {
+ console.error('操作失败:', err)
+ return {
+ success: false,
+ error: err.message
+ }
+ }
+}
+
+/**
+ * 添加纪念日
+ */
+async function addAnniversary(openid, anniversary) {
+ const res = await db.collection('anniversaries').add({
+ data: {
+ ...anniversary,
+ openid,
+ createTime: db.serverDate(),
+ updateTime: db.serverDate()
+ }
+ })
+
+ return {
+ success: true,
+ id: res._id
+ }
+}
+
+/**
+ * 更新纪念日
+ */
+async function updateAnniversary(openid, anniversary) {
+ const { id, ...updateData } = anniversary
+
+ await db.collection('anniversaries')
+ .where({
+ _id: id,
+ openid
+ })
+ .update({
+ data: {
+ ...updateData,
+ updateTime: db.serverDate()
+ }
+ })
+
+ return {
+ success: true
+ }
+}
+
+/**
+ * 删除纪念日
+ */
+async function deleteAnniversary(openid, id) {
+ await db.collection('anniversaries')
+ .where({
+ _id: id,
+ openid
+ })
+ .remove()
+
+ return {
+ success: true
+ }
+}
+
+/**
+ * 批量同步纪念日
+ */
+async function syncAnniversaries(openid, anniversaries) {
+ // 先删除用户的所有纪念日
+ await db.collection('anniversaries')
+ .where({
+ openid
+ })
+ .remove()
+
+ // 批量添加
+ const tasks = anniversaries.map(anniversary => {
+ return db.collection('anniversaries').add({
+ data: {
+ ...anniversary,
+ openid,
+ createTime: db.serverDate(),
+ updateTime: db.serverDate()
+ }
+ })
+ })
+
+ await Promise.all(tasks)
+
+ return {
+ success: true,
+ count: anniversaries.length
+ }
+}
+
+/**
+ * 获取用户所有纪念日
+ */
+async function getAnniversaries(openid) {
+ const res = await db.collection('anniversaries')
+ .where({
+ openid
+ })
+ .get()
+
+ return {
+ success: true,
+ data: res.data
+ }
+}
+
diff --git a/cloudfunctions/syncAnniversary/package.json b/cloudfunctions/syncAnniversary/package.json
new file mode 100644
index 0000000..5d0a126
--- /dev/null
+++ b/cloudfunctions/syncAnniversary/package.json
@@ -0,0 +1,10 @@
+{
+ "name": "syncAnniversary",
+ "version": "1.0.0",
+ "description": "同步纪念日数据",
+ "main": "index.js",
+ "dependencies": {
+ "wx-server-sdk": "~2.6.3"
+ }
+}
+
diff --git a/pages/add-anniversary/add-anniversary.js b/pages/add-anniversary/add-anniversary.js
index ffad185..d2669ad 100644
--- a/pages/add-anniversary/add-anniversary.js
+++ b/pages/add-anniversary/add-anniversary.js
@@ -1,6 +1,7 @@
// add-anniversary.js
const storage = require('../../utils/storage')
const dateUtils = require('../../utils/date')
+const api = require('../../utils/api')
Page({
data: {
@@ -188,11 +189,32 @@ Page({
*/
onRemindDaysChange(e) {
const index = parseInt(e.detail.value)
- const days = [3, 7, 14, 30, 7][index]
- this.setData({
- remindDaysIndex: index,
- 'formData.remindDays': days
- })
+ this.setData({ remindDaysIndex: index })
+ if (index === 4) {
+ // 自定义天数
+ wx.showModal({
+ title: '自定义提前天数',
+ editable: true,
+ placeholderText: '请输入天数(1-365)',
+ success: (res) => {
+ if (res.confirm) {
+ const days = parseInt(res.content)
+ if (!days || days < 1 || days > 365) {
+ wx.showToast({ title: '请输入1-365之间的天数', icon: 'none' })
+ this.setData({ remindDaysIndex: 1, 'formData.remindDays': 7 })
+ return
+ }
+ this.setData({ 'formData.remindDays': days })
+ } else {
+ // 取消则回到默认7天
+ this.setData({ remindDaysIndex: 1, 'formData.remindDays': 7 })
+ }
+ }
+ })
+ } else {
+ const days = [3, 7, 14, 30][index]
+ this.setData({ 'formData.remindDays': days })
+ }
},
/**
@@ -214,8 +236,8 @@ Page({
/**
* 提交
*/
- onSubmit() {
- const { formData, personId, anniversaryId } = this.data
+ async onSubmit() {
+ const { formData, personId, anniversaryId, personList } = this.data
// 验证关联人员
if (!personId) {
@@ -235,14 +257,36 @@ Page({
return
}
+ // 如果开启了提醒,请求订阅消息授权
+ if (formData.remindEnabled) {
+ try {
+ await this.requestSubscribe()
+ } catch (err) {
+ console.log('用户拒绝订阅消息')
+ // 继续保存,即使用户拒绝订阅
+ }
+ }
+
+ // 获取人员名称
+ const person = personList.find(p => p.id === personId)
+ const personName = person ? person.name : ''
+
if (anniversaryId) {
// 编辑模式
const success = storage.updateAnniversary(anniversaryId, {
personId,
+ personName,
...formData
})
if (success) {
+ // 同步到云端
+ this.syncToCloud(anniversaryId, {
+ personId,
+ personName,
+ ...formData
+ }, 'update')
+
wx.showToast({ title: '保存成功', icon: 'success' })
setTimeout(() => wx.navigateBack(), 1500)
}
@@ -250,14 +294,55 @@ Page({
// 新增模式
const newAnniversary = storage.addAnniversary({
personId,
+ personName,
...formData
})
if (newAnniversary) {
+ // 同步到云端
+ this.syncToCloud(newAnniversary.id, newAnniversary, 'add')
+
wx.showToast({ title: '添加成功', icon: 'success' })
setTimeout(() => wx.navigateBack(), 1500)
}
}
+ },
+
+ /**
+ * 请求订阅消息授权
+ */
+ requestSubscribe() {
+ return new Promise((resolve, reject) => {
+ wx.requestSubscribeMessage({
+ tmplIds: ['6J7Stt-lu7DKU6jblJ0nZGq_D81z5glnksf7qWfy5Yw'],
+ success: (res) => {
+ console.log('订阅消息授权结果:', res)
+ resolve(res)
+ },
+ fail: (err) => {
+ console.error('订阅消息授权失败:', err)
+ reject(err)
+ }
+ })
+ })
+ },
+
+ /**
+ * 同步到自建后端
+ */
+ async syncToCloud(id, data, action) {
+ try {
+ const openid = wx.getStorageSync('openid')
+ if (!openid) {
+ console.log('未获取到openid,跳过云端同步')
+ return
+ }
+ const res = await api.anniversary(action, { id, ...data })
+ console.log('云端同步成功:', res)
+ } catch (err) {
+ console.error('云端同步失败:', err)
+ // 不影响本地保存
+ }
}
})
diff --git a/pages/add-anniversary/add-anniversary.wxss b/pages/add-anniversary/add-anniversary.wxss
index 01b9dcc..810aa07 100644
--- a/pages/add-anniversary/add-anniversary.wxss
+++ b/pages/add-anniversary/add-anniversary.wxss
@@ -6,7 +6,7 @@
}
.form {
- padding: 32rpx;
+ padding: 0 32rpx 32rpx;
}
.form-item {
@@ -15,6 +15,11 @@
padding: 32rpx;
margin-bottom: 24rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
+ box-sizing: border-box;
+}
+
+.form-item:first-child {
+ margin-top: 6rpx;
}
.label {
@@ -100,36 +105,57 @@
}
.textarea {
+ width: 100%;
background-color: #f5f5f5;
border-radius: 8rpx;
padding: 24rpx;
font-size: 28rpx;
min-height: 160rpx;
+ box-sizing: border-box;
}
.buttons {
display: flex;
gap: 24rpx;
margin-top: 40rpx;
+ padding: 0 32rpx 32rpx;
}
.btn {
flex: 1;
- height: 88rpx;
- line-height: 88rpx;
- border-radius: 16rpx;
+ height: 96rpx;
+ line-height: 96rpx;
+ border-radius: 48rpx;
font-size: 32rpx;
+ font-weight: 600;
border: none;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+ box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
}
.btn-cancel {
- background-color: #f5f5f5;
+ background: linear-gradient(135deg, #f5f7fa 0%, #e8eaf0 100%);
color: #666;
+ border: 2rpx solid rgba(102, 126, 234, 0.2);
+}
+
+.btn-cancel:active {
+ transform: scale(0.98);
+ box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08);
}
.btn-submit {
- background: linear-gradient(135deg, #07c160 0%, #06ad56 100%);
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: #fff;
+ box-shadow: 0 8rpx 24rpx rgba(102, 126, 234, 0.4);
+}
+
+.btn-submit:active {
+ transform: scale(0.98);
+ box-shadow: 0 4rpx 16rpx rgba(102, 126, 234, 0.3);
}
.btn-cancel::after,
diff --git a/pages/add-person/add-person.wxss b/pages/add-person/add-person.wxss
index 28c05c4..b40248b 100644
--- a/pages/add-person/add-person.wxss
+++ b/pages/add-person/add-person.wxss
@@ -1,7 +1,7 @@
/**add-person.wxss**/
.container {
min-height: 100vh;
- background-color: #f5f5f5;
+ background: linear-gradient(180deg, rgba(102, 126, 234, 0.08) 0%, transparent 30%);
padding-bottom: 120rpx;
}
@@ -10,16 +10,21 @@
}
.form-item {
- background-color: #fff;
- border-radius: 16rpx;
- padding: 32rpx;
+ background: linear-gradient(135deg, #ffffff 0%, #f8f9ff 100%);
+ border-radius: 24rpx;
+ padding: 36rpx;
margin-bottom: 24rpx;
- box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
+ box-shadow: 0 8rpx 32rpx rgba(102, 126, 234, 0.12);
+ border: 2rpx solid rgba(255, 255, 255, 0.8);
}
.label {
font-size: 28rpx;
- color: #333;
+ font-weight: 600;
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
margin-bottom: 24rpx;
display: block;
}
@@ -27,6 +32,7 @@
.label.required::after {
content: ' *';
color: #ff5722;
+ -webkit-text-fill-color: #ff5722;
}
/* 头像上传 */
@@ -38,7 +44,9 @@
width: 200rpx;
height: 200rpx;
border-radius: 50%;
- background-color: #f0f0f0;
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+ border: 6rpx solid rgba(255, 255, 255, 0.9);
+ box-shadow: 0 8rpx 24rpx rgba(102, 126, 234, 0.3);
}
.avatar-placeholder {
@@ -46,69 +54,107 @@
height: 200rpx;
margin: 0 auto;
border-radius: 50%;
- background-color: #f5f5f5;
+ background: linear-gradient(135deg, rgba(102, 126, 234, 0.1) 0%, rgba(118, 75, 162, 0.1) 100%);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
- border: 2px dashed #ddd;
+ border: 4rpx dashed rgba(102, 126, 234, 0.4);
+ transition: all 0.3s ease;
+}
+
+.avatar-placeholder:active {
+ transform: scale(0.95);
+ background: linear-gradient(135deg, rgba(102, 126, 234, 0.15) 0%, rgba(118, 75, 162, 0.15) 100%);
}
.avatar-placeholder .icon {
- font-size: 60rpx;
+ font-size: 64rpx;
display: block;
margin-bottom: 16rpx;
+ filter: grayscale(0.5);
}
.avatar-placeholder .text {
font-size: 24rpx;
- color: #999;
+ color: #667eea;
+ font-weight: 500;
}
.input {
- background-color: #f5f5f5;
- border-radius: 8rpx;
+ background-color: #f8f9fa;
+ border-radius: 12rpx;
padding: 24rpx;
font-size: 28rpx;
+ border: 2rpx solid transparent;
+ transition: all 0.3s ease;
+}
+
+.input:focus {
+ background-color: #fff;
+ border-color: #667eea;
}
.textarea {
- background-color: #f5f5f5;
- border-radius: 8rpx;
+ background-color: #f8f9fa;
+ border-radius: 12rpx;
padding: 24rpx;
font-size: 28rpx;
min-height: 160rpx;
+ border: 2rpx solid transparent;
+ transition: all 0.3s ease;
+}
+
+.textarea:focus {
+ background-color: #fff;
+ border-color: #667eea;
}
.buttons {
display: flex;
gap: 24rpx;
margin-top: 40rpx;
+ padding: 0 32rpx 32rpx;
}
.btn {
flex: 1;
- height: 88rpx;
- line-height: 88rpx;
- border-radius: 16rpx;
+ height: 96rpx;
+ line-height: 96rpx;
+ border-radius: 48rpx;
font-size: 32rpx;
+ font-weight: 600;
border: none;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+ box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
}
.btn-cancel {
- background-color: #f5f5f5;
+ background: linear-gradient(135deg, #f5f7fa 0%, #e8eaf0 100%);
color: #666;
+ border: 2rpx solid rgba(102, 126, 234, 0.2);
+}
+
+.btn-cancel:active {
+ transform: scale(0.98);
+ box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08);
}
.btn-submit {
- background: linear-gradient(135deg, #07c160 0%, #06ad56 100%);
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: #fff;
+ box-shadow: 0 8rpx 24rpx rgba(102, 126, 234, 0.4);
}
-.btn-cancel::after {
- border: none;
+.btn-submit:active {
+ transform: scale(0.98);
+ box-shadow: 0 4rpx 16rpx rgba(102, 126, 234, 0.3);
}
+.btn-cancel::after,
.btn-submit::after {
border: none;
}
diff --git a/pages/calendar/calendar.js b/pages/calendar/calendar.js
index 5b73eb8..a3dc04e 100644
--- a/pages/calendar/calendar.js
+++ b/pages/calendar/calendar.js
@@ -1,11 +1,12 @@
// calendar.js
const storage = require('../../utils/storage')
const dateUtils = require('../../utils/date')
+const { TYPE_NAMES, TYPE_ICONS, IMPORTANCE_COLORS } = require('../../utils/constants')
Page({
data: {
- currentYear: 2024,
- currentMonth: 1,
+ currentYear: new Date().getFullYear(),
+ currentMonth: new Date().getMonth() + 1,
calendarDays: [],
monthEvents: []
},
@@ -20,100 +21,75 @@ Page({
this.loadMonthEvents()
},
+ /**
+ * 构建当月事件索引 { "day": [anniversary, ...] }
+ */
+ buildEventIndex(anniversaries, year, month) {
+ const index = {}
+ for (const a of anniversaries) {
+ if (a.solarYear === year && a.solarMonth === month) {
+ const key = String(a.solarDay)
+ if (!index[key]) index[key] = []
+ index[key].push(a)
+ }
+ }
+ return index
+ },
+
/**
* 渲染日历
*/
renderCalendar() {
const { currentYear, currentMonth } = this.data
const anniversaries = storage.getAnniversaries()
-
- // 获取本月第一天是星期几
+
+ // 预建事件索引,避免 O(n×m) 过滤
+ const eventIndex = this.buildEventIndex(anniversaries, currentYear, currentMonth)
+
const firstDay = new Date(currentYear, currentMonth - 1, 1)
const startWeekday = firstDay.getDay()
-
- // 获取本月天数
const daysInMonth = new Date(currentYear, currentMonth, 0).getDate()
-
- // 获取上个月的天数
const prevMonthDays = new Date(currentYear, currentMonth - 1, 0).getDate()
-
- // 构建日历天数数组
+
const calendarDays = []
- const today = new Date()
-
+
// 填充上个月的日期
for (let i = startWeekday - 1; i >= 0; i--) {
const day = prevMonthDays - i
- calendarDays.push({
- day,
- date: new Date(currentYear, currentMonth - 2, day),
- isToday: false,
- isOtherMonth: true,
- events: [],
- hasMore: false
- })
+ calendarDays.push({ day, isToday: false, isOtherMonth: true, events: [], hasMore: false })
}
-
+
// 填充本月的日期
for (let day = 1; day <= daysInMonth; day++) {
const date = new Date(currentYear, currentMonth - 1, day)
const isToday = dateUtils.isToday(date)
-
- // 查找该日期的纪念日
- const events = anniversaries
- .filter(a => this.isAnniversaryOnDate(a, date))
- .map(a => ({
- id: a.id,
- color: this.getEventColor(a)
- }))
- .slice(0, 3)
-
+ const allEvents = eventIndex[String(day)] || []
+ const events = allEvents.slice(0, 3).map(a => ({ id: a.id, color: this.getEventColor(a) }))
+
calendarDays.push({
day,
- date,
isToday,
isOtherMonth: false,
events,
- hasMore: events.length > 2,
- moreCount: anniversaries.filter(a => this.isAnniversaryOnDate(a, date)).length - 2
+ hasMore: allEvents.length > 3,
+ moreCount: allEvents.length - 3
})
}
-
+
// 填充下个月的日期(补全6行)
const remainingDays = 42 - calendarDays.length
for (let day = 1; day <= remainingDays; day++) {
- calendarDays.push({
- day,
- date: new Date(currentYear, currentMonth, day),
- isToday: false,
- isOtherMonth: true,
- events: [],
- hasMore: false
- })
+ calendarDays.push({ day, isToday: false, isOtherMonth: true, events: [], hasMore: false })
}
-
- this.setData({ calendarDays })
- },
- /**
- * 判断纪念日是否在某日期
- */
- isAnniversaryOnDate(anniversary, date) {
- return anniversary.solarYear === date.getFullYear() &&
- anniversary.solarMonth === date.getMonth() + 1 &&
- anniversary.solarDay === date.getDate()
+ this.setData({ calendarDays })
},
/**
* 获取事件颜色
*/
getEventColor(anniversary) {
- const colors = {
- high: '#ff5722',
- medium: '#ff9800',
- low: '#07c160'
- }
- return colors[anniversary.importance] || '#07c160'
+ return IMPORTANCE_COLORS[anniversary.importance] || '#07c160'
},
/**
@@ -150,28 +126,14 @@ Page({
* 获取类型图标
*/
getTypeIcon(type) {
- const icons = {
- birthday: '🎂',
- lunar_birthday: '🌙',
- wedding: '💍',
- engagement: '💕',
- other: '📅'
- }
- return icons[type] || '📅'
+ return TYPE_ICONS[type] || '📅'
},
/**
* 获取类型名称
*/
getTypeName(type) {
- const names = {
- birthday: '公历生日',
- lunar_birthday: '农历生日',
- wedding: '结婚纪念日',
- engagement: '订婚纪念日',
- other: '其他纪念日'
- }
- return names[type] || '其他'
+ return TYPE_NAMES[type] || '其他'
},
/**
diff --git a/pages/calendar/calendar.wxml b/pages/calendar/calendar.wxml
index c02dbd2..123ba8d 100644
--- a/pages/calendar/calendar.wxml
+++ b/pages/calendar/calendar.wxml
@@ -12,7 +12,9 @@
diff --git a/pages/calendar/calendar.wxss b/pages/calendar/calendar.wxss
index 87d134b..3e33eff 100644
--- a/pages/calendar/calendar.wxss
+++ b/pages/calendar/calendar.wxss
@@ -5,43 +5,61 @@
}
.calendar-header {
- background-color: #fff;
- padding: 32rpx;
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+ padding: 40rpx 32rpx;
display: flex;
align-items: center;
justify-content: space-between;
- border-bottom: 1px solid #f0f0f0;
+ box-shadow: 0 4rpx 16rpx rgba(102, 126, 234, 0.2);
}
.month-navigation {
display: flex;
align-items: center;
- gap: 32rpx;
+ gap: 24rpx;
}
.nav-btn {
- font-size: 48rpx;
- color: #07c160;
+ font-size: 40rpx;
+ color: #fff;
font-weight: 300;
- width: 60rpx;
- text-align: center;
+ width: 56rpx;
+ height: 56rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background-color: rgba(255, 255, 255, 0.2);
+ border-radius: 50%;
+ transition: all 0.2s;
+}
+
+.nav-btn:active {
+ background-color: rgba(255, 255, 255, 0.3);
+ transform: scale(0.95);
}
.month-title {
font-size: 36rpx;
font-weight: 600;
- color: #333;
+ color: #fff;
min-width: 240rpx;
text-align: center;
}
.today-btn {
- padding: 12rpx 32rpx;
- background-color: #f5f5f5;
- color: #666;
+ padding: 14rpx 32rpx;
+ background-color: rgba(255, 255, 255, 0.25);
+ color: #fff;
border-radius: 40rpx;
- font-size: 24rpx;
+ font-size: 26rpx;
border: none;
+ font-weight: 600;
+ transition: all 0.2s;
+}
+
+.today-btn:active {
+ background-color: rgba(255, 255, 255, 0.35);
+ transform: scale(0.95);
}
.today-btn::after {
@@ -49,96 +67,137 @@
}
.week-header {
- display: flex;
- background-color: #fff;
- border-bottom: 1px solid #f0f0f0;
+ display: grid;
+ grid-template-columns: repeat(7, 1fr);
+ background: linear-gradient(to bottom, #fff 0%, #fafafa 100%);
+ padding: 20rpx 24rpx 12rpx 24rpx;
+ gap: 12rpx;
+ border-bottom: 2rpx solid #f0f0f0;
+ box-sizing: border-box;
}
.week-title {
- flex: 1;
- text-align: center;
- padding: 20rpx 0;
- font-size: 24rpx;
- color: #999;
- font-weight: 500;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: 60rpx;
+ font-size: 26rpx;
+ color: #888;
+ font-weight: 600;
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+.week-title text {
+ display: block;
}
.calendar-content {
height: calc(100vh - 200rpx);
+ background-color: #f5f5f5;
}
.calendar-grid {
display: grid;
grid-template-columns: repeat(7, 1fr);
- background-color: #fff;
+ background-color: #f5f5f5;
+ padding: 16rpx 24rpx 16rpx 24rpx;
+ gap: 12rpx;
+ box-sizing: border-box;
}
.calendar-cell {
- min-height: 120rpx;
- border: 1px solid #f0f0f0;
- padding: 8rpx;
+ min-height: 100rpx;
+ background-color: #fff;
+ border-radius: 12rpx;
+ padding: 12rpx 8rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
+ box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
+ transition: all 0.2s;
+ box-sizing: border-box;
+ margin: 0;
}
.calendar-cell.other-month {
- background-color: #fafafa;
+ background-color: transparent;
+ box-shadow: none;
+}
+
+.calendar-cell.today {
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+ box-shadow: 0 8rpx 16rpx rgba(102, 126, 234, 0.3);
+ transform: scale(1.05);
}
.calendar-cell.today .date-num {
- background-color: #07c160;
color: #fff;
- border-radius: 50%;
- width: 48rpx;
- height: 48rpx;
- line-height: 48rpx;
- text-align: center;
+ font-weight: 700;
}
.date-num {
- font-size: 28rpx;
+ font-size: 32rpx;
color: #333;
margin-bottom: 8rpx;
+ font-weight: 600;
}
.calendar-cell.other-month .date-num {
- color: #ccc;
+ color: #d0d0d0;
+ font-weight: 400;
}
.events {
display: flex;
- gap: 4rpx;
+ gap: 6rpx;
+ flex-wrap: wrap;
+ justify-content: center;
+ max-width: 100%;
}
.event-dot {
- width: 12rpx;
- height: 12rpx;
+ width: 8rpx;
+ height: 8rpx;
border-radius: 50%;
+ box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.15);
+}
+
+.calendar-cell.today .event-dot {
+ background-color: #fff !important;
}
.more-text {
- font-size: 20rpx;
+ font-size: 18rpx;
color: #999;
margin-top: 4rpx;
+ font-weight: 500;
+}
+
+.calendar-cell.today .more-text {
+ color: #fff;
}
/* 事件列表 */
.events-list {
- padding: 32rpx;
+ padding: 32rpx 24rpx;
}
.section-title {
font-size: 32rpx;
- font-weight: 600;
+ font-weight: 700;
color: #333;
margin-bottom: 24rpx;
+ padding-left: 16rpx;
+ border-left: 6rpx solid #667eea;
}
.empty-state {
text-align: center;
padding: 120rpx 40rpx;
+ opacity: 0.6;
}
.empty-state .icon {
@@ -150,14 +209,17 @@
.empty-state .text {
font-size: 28rpx;
color: #999;
+ line-height: 1.6;
}
.event-card {
- background-color: #fff;
+ background: linear-gradient(135deg, #fff 0%, #fafafa 100%);
border-radius: 16rpx;
padding: 32rpx;
- margin-bottom: 24rpx;
- box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
+ margin-bottom: 20rpx;
+ box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
+ border: 2rpx solid rgba(102, 126, 234, 0.1);
+ transition: all 0.3s;
}
.event-header {
@@ -190,26 +252,31 @@
}
.lunar-badge {
- padding: 4rpx 12rpx;
- background-color: #e3f2fd;
+ padding: 6rpx 16rpx;
+ background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%);
color: #1976d2;
- border-radius: 4rpx;
+ border-radius: 20rpx;
font-size: 20rpx;
+ font-weight: 600;
+ box-shadow: 0 2rpx 8rpx rgba(25, 118, 210, 0.15);
}
.status {
font-size: 22rpx;
- padding: 4rpx 12rpx;
- border-radius: 4rpx;
+ padding: 6rpx 16rpx;
+ border-radius: 20rpx;
+ font-weight: 600;
}
.status.urgent {
- background-color: #fff3f0;
+ background: linear-gradient(135deg, #ffe0db 0%, #ffccbc 100%);
color: #ff5722;
+ box-shadow: 0 2rpx 8rpx rgba(255, 87, 34, 0.15);
}
.status.warning {
- background-color: #fff8e6;
+ background: linear-gradient(135deg, #fff8e1 0%, #ffecb3 100%);
color: #ff9800;
+ box-shadow: 0 2rpx 8rpx rgba(255, 152, 0, 0.15);
}
diff --git a/pages/index/index.js b/pages/index/index.js
index 20fcb89..7c67069 100644
--- a/pages/index/index.js
+++ b/pages/index/index.js
@@ -1,13 +1,17 @@
// index.js
const storage = require('../../utils/storage')
const dateUtils = require('../../utils/date')
+const { TYPE_NAMES } = require('../../utils/constants')
Page({
data: {
persons: [],
- originalPersons: [], // 原始数据备份
+ originalPersons: [],
searchKeyword: '',
- currentFilter: 'all'
+ currentFilter: 'all',
+ totalCount: 0,
+ upcomingCount: 0,
+ todayText: ''
},
onLoad() {
@@ -15,7 +19,6 @@ Page({
},
onShow() {
- // 每次显示页面时刷新数据
this.loadPersons()
},
@@ -25,32 +28,24 @@ Page({
loadPersons() {
const persons = storage.getPersons()
const anniversaries = storage.getAnniversaries()
-
- // 为每个人员添加纪念日信息
+
const personsWithAnniversaries = persons.map(person => {
const personAnniversaries = anniversaries.filter(a => a.personId === person.id)
-
- // 找到最近的纪念日
+
let nextAnniversary = null
if (personAnniversaries.length > 0) {
- const today = new Date()
const upcoming = personAnniversaries
.map(a => {
- // 如果是农历,需要特殊处理
- const date = new Date(a.solarYear, a.solarMonth - 1, a.solarDay)
- return {
- ...a,
- date,
- daysUntil: dateUtils.getDaysUntil(date)
- }
+ const { date, daysUntil } = dateUtils.getNextOccurrence(a.solarMonth, a.solarDay)
+ return { ...a, date, daysUntil }
})
- .filter(a => a.daysUntil >= 0)
.sort((a, b) => a.daysUntil - b.daysUntil)
-
+
if (upcoming.length > 0) {
const next = upcoming[0]
nextAnniversary = {
type: next.type,
+ typeName: this.getTypeName(next.type, next.customTypeName),
dateText: dateUtils.formatDate(next.date, 'MM月DD日'),
daysUntil: next.daysUntil,
daysUntilText: this.formatDaysUntil(next.daysUntil)
@@ -58,14 +53,9 @@ Page({
}
}
- return {
- ...person,
- anniversaryCount: personAnniversaries.length,
- nextAnniversary
- }
+ return { ...person, anniversaryCount: personAnniversaries.length, nextAnniversary }
})
- // 按最近的纪念日排序
const sorted = personsWithAnniversaries.sort((a, b) => {
if (!a.nextAnniversary && !b.nextAnniversary) return 0
if (!a.nextAnniversary) return 1
@@ -73,10 +63,18 @@ Page({
return a.nextAnniversary.daysUntil - b.nextAnniversary.daysUntil
})
- this.setData({
- persons: sorted,
- originalPersons: sorted
- })
+ const today = new Date()
+ const weekdays = ['日', '一', '二', '三', '四', '五', '六']
+ const todayText = `${today.getMonth() + 1}月${today.getDate()}日 周${weekdays[today.getDay()]}`
+ const upcomingCount = sorted.filter(p => p.nextAnniversary && p.nextAnniversary.daysUntil <= 7).length
+
+ this.setData({ originalPersons: sorted, totalCount: sorted.length, upcomingCount, todayText })
+
+ if (this.data.currentFilter === 'all' && !this.data.searchKeyword) {
+ this.setData({ persons: sorted })
+ } else {
+ this.filterPersons()
+ }
},
/**
@@ -90,6 +88,14 @@ Page({
return `还有${Math.floor(days / 30)}个月`
},
+ /**
+ * 获取类型名称
+ */
+ getTypeName(type, customName) {
+ if (type === 'other' && customName) return customName
+ return TYPE_NAMES[type] || '纪念日'
+ },
+
/**
* 搜索输入
*/
@@ -104,8 +110,9 @@ Page({
*/
onFilterTap(e) {
const filter = e.currentTarget.dataset.filter
- this.setData({ currentFilter: filter })
- this.filterPersons()
+ this.setData({ currentFilter: filter }, () => {
+ this.filterPersons()
+ })
},
/**
@@ -113,6 +120,7 @@ Page({
*/
filterPersons() {
const { originalPersons, searchKeyword, currentFilter } = this.data
+ const anniversaries = storage.getAnniversaries()
let filtered = [...originalPersons]
@@ -124,12 +132,39 @@ Page({
)
}
- // 类型筛选(暂时保留,后续可以实现更精确的筛选)
- // if (currentFilter !== 'all') {
- // // 可以实现更精确的筛选逻辑
- // }
+ // 类型筛选
+ if (currentFilter !== 'all') {
+ filtered = filtered.filter(person => {
+ const personAnniversaries = anniversaries.filter(a => a.personId === person.id)
+
+ if (currentFilter === 'birthday') {
+ // 生日筛选:只显示有生日类型的人(公历生日或农历生日)
+ return personAnniversaries.some(a =>
+ a.type === 'birthday' || a.type === 'lunar_birthday'
+ )
+ } else if (currentFilter === 'anniversary') {
+ // 纪念日筛选:只显示有纪念日类型的人(结婚、订婚、其他)
+ return personAnniversaries.some(a =>
+ a.type === 'wedding' || a.type === 'engagement' || a.type === 'other'
+ )
+ } else if (currentFilter === 'upcoming') {
+ // 即将到来:只显示7天内有纪念日的人
+ return person.nextAnniversary && person.nextAnniversary.daysUntil <= 7
+ }
+
+ return true
+ })
+ }
- this.setData({ persons: filtered })
+ // 排序:与 loadPersons() 保持一致,按最近的纪念日排序
+ const sorted = filtered.sort((a, b) => {
+ if (!a.nextAnniversary && !b.nextAnniversary) return 0
+ if (!a.nextAnniversary) return 1
+ if (!b.nextAnniversary) return -1
+ return a.nextAnniversary.daysUntil - b.nextAnniversary.daysUntil
+ })
+
+ this.setData({ persons: sorted })
},
/**
diff --git a/pages/index/index.wxml b/pages/index/index.wxml
index a587af6..388e700 100644
--- a/pages/index/index.wxml
+++ b/pages/index/index.wxml
@@ -1,56 +1,112 @@
-
+
+
+
+
+
-
-
+
+
+ 🔍
+
+
-
- 筛选:
-
- 全部
- 生日
- 纪念日
- 即将到来
-
-
+
+
+ 全部
+ 🎂 生日
+ 💍 纪念日
+ ⏰ 即将到来
+
+
-
-
- 📅
- 还没有添加任何人
- 点击右下角 + 添加第一个
+
+
+
+
+ 🌟
+ 还没有添加任何人
+ 点击右下角 + 开始添加
-
-
- +
+ +
-
+
diff --git a/pages/index/index.wxss b/pages/index/index.wxss
index b216a3b..d31e8f8 100644
--- a/pages/index/index.wxss
+++ b/pages/index/index.wxss
@@ -1,193 +1,410 @@
-/**index.wxss**/
-.container {
- min-height: 100vh;
- background-color: #f5f5f5;
+/* index.wxss */
+
+page {
+ background: #f1f4f9;
}
-/* 搜索栏 */
-.search-bar {
- padding: 24rpx;
- background-color: #fff;
- border-bottom: 1px solid #f0f0f0;
-}
-
-.search-input {
- background-color: #f5f5f5;
- border-radius: 40rpx;
- padding: 24rpx 32rpx;
- font-size: 28rpx;
-}
-
-/* 筛选栏 */
-.filter-bar {
+.page {
display: flex;
- align-items: center;
- padding: 20rpx 24rpx;
- background-color: #fff;
- border-bottom: 1px solid #f0f0f0;
+ flex-direction: column;
+ height: 100vh;
+ background: #f1f4f9;
}
-.filter-label {
- font-size: 26rpx;
- color: #666;
- margin-right: 16rpx;
- white-space: nowrap;
+/* ───── Header ───── */
+.header {
+ background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
+ padding: 48rpx 36rpx 40rpx;
+ flex-shrink: 0;
}
-.filter-scroll {
- white-space: nowrap;
-}
-
-.filter-item {
- display: inline-block;
- padding: 12rpx 32rpx;
- margin-right: 16rpx;
- border-radius: 40rpx;
- font-size: 26rpx;
- background-color: #f5f5f5;
- color: #666;
-}
-
-.filter-item.active {
- background-color: #07c160;
- color: #fff;
-}
-
-/* 人员列表 */
-.person-list {
- height: calc(100vh - 200rpx);
- padding: 24rpx;
-}
-
-.person-card {
- background-color: #fff;
- border-radius: 16rpx;
- padding: 32rpx;
- margin-bottom: 24rpx;
- box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
-}
-
-.person-header {
+.header-top {
display: flex;
- align-items: center;
+ align-items: flex-start;
+ justify-content: space-between;
+ margin-bottom: 32rpx;
}
-.avatar {
- width: 100rpx;
- height: 100rpx;
- border-radius: 50%;
- margin-right: 24rpx;
- background-color: #f0f0f0;
-}
-
-.person-info {
- flex: 1;
+.header-left {
display: flex;
flex-direction: column;
}
-.person-name {
- font-size: 32rpx;
- font-weight: 600;
- color: #333;
- margin-bottom: 8rpx;
+.header-title {
+ font-size: 44rpx;
+ font-weight: 700;
+ color: #fff;
+ line-height: 1.2;
+ letter-spacing: 2rpx;
}
-.person-nickname {
- font-size: 24rpx;
- color: #999;
+.header-date {
+ font-size: 26rpx;
+ color: rgba(255, 255, 255, 0.7);
+ margin-top: 8rpx;
}
-.person-count {
- text-align: right;
+.header-icon {
+ font-size: 64rpx;
+ opacity: 0.9;
}
-.count-text {
- font-size: 36rpx;
- font-weight: 600;
- color: #07c160;
- display: block;
-}
-
-.count-label {
- font-size: 22rpx;
- color: #999;
-}
-
-/* 最近的纪念日 */
-.next-anniversary {
- margin-top: 20rpx;
- padding-top: 20rpx;
- border-top: 1px solid #f0f0f0;
+.stats-row {
display: flex;
align-items: center;
- font-size: 26rpx;
- color: #666;
+ background: rgba(255, 255, 255, 0.15);
+ border-radius: 20rpx;
+ padding: 20rpx 32rpx;
+ backdrop-filter: blur(8rpx);
}
-.next-label {
- margin-right: 8rpx;
-}
-
-.next-text {
+.stat-item {
+ display: flex;
+ align-items: baseline;
+ gap: 8rpx;
flex: 1;
+ justify-content: center;
}
-.days-text {
- color: #07c160;
- font-weight: 500;
+.stat-num {
+ font-size: 48rpx;
+ font-weight: 700;
+ color: #fff;
+ line-height: 1;
}
-.days-text.urgent {
- color: #ff5722;
+.stat-num-urgent {
+ color: #fbbf24;
+}
+
+.stat-label {
+ font-size: 24rpx;
+ color: rgba(255, 255, 255, 0.75);
+}
+
+.stat-sep {
+ width: 2rpx;
+ height: 48rpx;
+ background: rgba(255, 255, 255, 0.25);
+ flex-shrink: 0;
+}
+
+/* ───── Search ───── */
+.search-wrap {
+ padding: 24rpx 24rpx 12rpx;
+ flex-shrink: 0;
+}
+
+.search-box {
+ display: flex;
+ align-items: center;
+ background: #fff;
+ border-radius: 48rpx;
+ padding: 20rpx 28rpx;
+ box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.07);
+}
+
+.search-icon {
+ font-size: 32rpx;
+ margin-right: 16rpx;
+ opacity: 0.6;
+}
+
+.search-input {
+ flex: 1;
+ font-size: 28rpx;
+ color: #1e293b;
+ line-height: 1.5;
+}
+
+.search-placeholder {
+ color: #94a3b8;
+}
+
+/* ───── Filter ───── */
+.filter-scroll {
+ flex-shrink: 0;
+ white-space: nowrap;
+}
+
+.filter-bar {
+ display: flex;
+ padding: 16rpx 24rpx 20rpx;
+ gap: 16rpx;
+}
+
+.filter-tab {
+ display: inline-flex;
+ align-items: center;
+ padding: 14rpx 28rpx;
+ border-radius: 48rpx;
+ font-size: 26rpx;
+ color: #64748b;
+ background: #fff;
+ box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
+ white-space: nowrap;
+ transition: all 0.2s ease;
+ flex-shrink: 0;
+}
+
+.tab-active {
+ background: #6366f1;
+ color: #fff;
+ box-shadow: 0 4rpx 16rpx rgba(99, 102, 241, 0.4);
+}
+
+/* ───── List ───── */
+.list {
+ flex: 1;
+ overflow: hidden;
+ padding: 0 24rpx;
+}
+
+/* ───── Card ───── */
+.card {
+ display: flex;
+ align-items: center;
+ background: #fff;
+ border-radius: 20rpx;
+ padding: 28rpx 28rpx 28rpx 24rpx;
+ margin-bottom: 20rpx;
+ box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
+ border-left: 6rpx solid #e2e8f0;
+ transition: transform 0.15s ease, box-shadow 0.15s ease;
+ position: relative;
+ overflow: hidden;
+}
+
+.card:active {
+ transform: scale(0.985);
+ box-shadow: 0 1rpx 6rpx rgba(0, 0, 0, 0.05);
+}
+
+.card-urgent {
+ border-left-color: #f97316;
+}
+
+.card-today {
+ border-left-color: #ef4444;
+}
+
+/* ───── Avatar ───── */
+.avatar-wrap {
+ width: 96rpx;
+ height: 96rpx;
+ border-radius: 50%;
+ margin-right: 24rpx;
+ flex-shrink: 0;
+ overflow: hidden;
+}
+
+.avatar-img {
+ width: 100%;
+ height: 100%;
+ border-radius: 50%;
+}
+
+.avatar-placeholder {
+ width: 100%;
+ height: 100%;
+ border-radius: 50%;
+ background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.avatar-initial {
+ font-size: 40rpx;
+ font-weight: 700;
+ color: #fff;
+}
+
+/* ───── Card body ───── */
+.card-body {
+ flex: 1;
+ min-width: 0;
+}
+
+.card-row-top {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 12rpx;
+}
+
+.name-group {
+ display: flex;
+ align-items: center;
+ gap: 12rpx;
+ min-width: 0;
+ flex: 1;
+ margin-right: 16rpx;
+}
+
+.card-name {
+ font-size: 32rpx;
font-weight: 600;
+ color: #1e293b;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
}
-/* 空状态 */
-.empty-state {
- padding: 160rpx 40rpx;
- text-align: center;
+.card-nickname {
+ font-size: 22rpx;
+ color: #94a3b8;
+ background: #f1f5f9;
+ padding: 4rpx 12rpx;
+ border-radius: 20rpx;
+ white-space: nowrap;
+ flex-shrink: 0;
}
-.empty-state .icon {
+/* ───── Badge ───── */
+.badge {
+ display: inline-flex;
+ align-items: center;
+ padding: 6rpx 18rpx;
+ border-radius: 24rpx;
+ flex-shrink: 0;
+}
+
+.badge-text {
+ font-size: 22rpx;
+ font-weight: 600;
+ white-space: nowrap;
+}
+
+.badge-today {
+ background: #fee2e2;
+}
+.badge-today .badge-text {
+ color: #ef4444;
+}
+
+.badge-hot {
+ background: #ffedd5;
+}
+.badge-hot .badge-text {
+ color: #f97316;
+}
+
+.badge-soon {
+ background: #fef9c3;
+}
+.badge-soon .badge-text {
+ color: #ca8a04;
+}
+
+.badge-month {
+ background: #ede9fe;
+}
+.badge-month .badge-text {
+ color: #7c3aed;
+}
+
+.badge-normal {
+ background: #f1f5f9;
+}
+.badge-normal .badge-text {
+ color: #64748b;
+}
+
+/* ───── Anniversary row ───── */
+.card-row-ann {
+ display: flex;
+ align-items: center;
+ gap: 8rpx;
+}
+
+.ann-icon {
+ font-size: 26rpx;
+ flex-shrink: 0;
+}
+
+.ann-info {
+ font-size: 26rpx;
+ color: #475569;
+ flex: 1;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.muted {
+ color: #94a3b8;
+}
+
+.ann-more {
+ font-size: 22rpx;
+ color: #6366f1;
+ background: #ede9fe;
+ padding: 4rpx 12rpx;
+ border-radius: 20rpx;
+ flex-shrink: 0;
+}
+
+/* ───── Empty state ───── */
+.empty {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 160rpx 40rpx 80rpx;
+}
+
+.empty-icon {
font-size: 120rpx;
- display: block;
margin-bottom: 32rpx;
}
-.empty-state .text {
- font-size: 28rpx;
- color: #999;
- display: block;
+.empty-title {
+ font-size: 32rpx;
+ font-weight: 600;
+ color: #475569;
margin-bottom: 16rpx;
}
-.empty-state .hint {
- font-size: 24rpx;
- color: #bbb;
- display: block;
+.empty-hint {
+ font-size: 26rpx;
+ color: #94a3b8;
+ background: #fff;
+ padding: 14rpx 32rpx;
+ border-radius: 40rpx;
+ box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
}
-/* 浮动按钮 */
+/* ───── List bottom padding ───── */
+.list-bottom {
+ height: 180rpx;
+}
+
+/* ───── FAB ───── */
.fab {
position: fixed;
bottom: 120rpx;
right: 40rpx;
- width: 100rpx;
- height: 100rpx;
+ width: 112rpx;
+ height: 112rpx;
border-radius: 50%;
- background: linear-gradient(135deg, #07c160 0%, #06ad56 100%);
- color: #fff;
+ background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
display: flex;
align-items: center;
justify-content: center;
- font-size: 60rpx;
- box-shadow: 0 8rpx 24rpx rgba(7, 193, 96, 0.3);
+ box-shadow: 0 12rpx 40rpx rgba(99, 102, 241, 0.5);
z-index: 100;
- transition: all 0.3s;
+ transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.2s ease;
}
.fab:active {
- transform: scale(0.95);
+ transform: scale(0.9);
+ box-shadow: 0 6rpx 20rpx rgba(99, 102, 241, 0.4);
}
+.fab-icon {
+ font-size: 64rpx;
+ color: #fff;
+ font-weight: 300;
+ line-height: 1;
+ margin-top: -4rpx;
+}
diff --git a/pages/person-detail/person-detail.js b/pages/person-detail/person-detail.js
index 943b379..397ace4 100644
--- a/pages/person-detail/person-detail.js
+++ b/pages/person-detail/person-detail.js
@@ -1,6 +1,7 @@
// person-detail.js
const storage = require('../../utils/storage')
const dateUtils = require('../../utils/date')
+const { TYPE_NAMES, TYPE_ICONS, IMPORTANCE_TEXTS } = require('../../utils/constants')
Page({
data: {
@@ -57,6 +58,7 @@ Page({
date,
dateText: dateUtils.formatDate(date, 'YYYY年MM月DD日'),
daysUntil,
+ daysUntilAbs: Math.abs(daysUntil), // 添加绝对值
typeIcon: this.getTypeIcon(a.type),
typeName: a.customTypeName || this.getTypeName(a.type),
importanceText: this.getImportanceText(a.importance)
@@ -73,40 +75,21 @@ Page({
* 获取类型图标
*/
getTypeIcon(type) {
- const icons = {
- birthday: '🎂',
- lunar_birthday: '🌙',
- wedding: '💍',
- engagement: '💕',
- other: '📅'
- }
- return icons[type] || '📅'
+ return TYPE_ICONS[type] || '📅'
},
/**
* 获取类型名称
*/
getTypeName(type) {
- const names = {
- birthday: '公历生日',
- lunar_birthday: '农历生日',
- wedding: '结婚纪念日',
- engagement: '订婚纪念日',
- other: '其他纪念日'
- }
- return names[type] || '其他'
+ return TYPE_NAMES[type] || '其他'
},
/**
* 获取重要程度文本
*/
getImportanceText(importance) {
- const texts = {
- high: '非常重要',
- medium: '重要',
- low: '一般'
- }
- return texts[importance] || '一般'
+ return IMPORTANCE_TEXTS[importance] || '一般'
},
/**
@@ -127,17 +110,12 @@ Page({
content: `确定要删除"${this.data.person.name}"吗?相关纪念日也将被删除。`,
success: (res) => {
if (res.confirm) {
- // 先删除相关纪念日
- const anniversaries = storage.getAnniversariesByPersonId(this.data.personId)
- anniversaries.forEach(a => storage.deleteAnniversary(a.id))
-
- // 再删除人员
- const success = storage.deletePerson(this.data.personId)
+ const success = storage.deletePersonWithAnniversaries(this.data.personId)
if (success) {
wx.showToast({ title: '删除成功', icon: 'success' })
- setTimeout(() => {
- wx.navigateBack()
- }, 1500)
+ setTimeout(() => wx.navigateBack(), 1500)
+ } else {
+ wx.showToast({ title: '删除失败,请重试', icon: 'none' })
}
}
}
diff --git a/pages/person-detail/person-detail.wxml b/pages/person-detail/person-detail.wxml
index 9bc8546..15e0995 100644
--- a/pages/person-detail/person-detail.wxml
+++ b/pages/person-detail/person-detail.wxml
@@ -46,9 +46,9 @@
今天
- 明天
- {{item.daysUntil}}天后
- 已过{{Math.abs(item.daysUntil)}}天
+ 明天
+ {{item.daysUntil}}天后
+ 已过{{item.daysUntilAbs}}天
diff --git a/pages/settings/settings.js b/pages/settings/settings.js
index 1d1b82a..b7a581d 100644
--- a/pages/settings/settings.js
+++ b/pages/settings/settings.js
@@ -69,29 +69,16 @@ Page({
success: (res) => {
try {
const data = JSON.parse(res.data)
- const success = storage.importData(data)
-
- if (success) {
- wx.showToast({
- title: '导入成功',
- icon: 'success'
- })
- setTimeout(() => {
- wx.reLaunch({
- url: '/pages/index/index'
- })
- }, 1500)
+ const result = storage.importData(data)
+
+ if (result.success) {
+ wx.showToast({ title: '导入成功', icon: 'success' })
+ setTimeout(() => wx.reLaunch({ url: '/pages/index/index' }), 1500)
} else {
- wx.showToast({
- title: '导入失败,请检查数据格式',
- icon: 'none'
- })
+ wx.showToast({ title: result.error || '导入失败,请检查数据格式', icon: 'none' })
}
} catch (e) {
- wx.showToast({
- title: '数据格式错误',
- icon: 'none'
- })
+ wx.showToast({ title: '数据格式错误', icon: 'none' })
}
}
})
diff --git a/pages/settings/settings.wxml b/pages/settings/settings.wxml
index a8ea9eb..d1c3d1b 100644
--- a/pages/settings/settings.wxml
+++ b/pages/settings/settings.wxml
@@ -1,46 +1,119 @@
-
-
-
-
- 数据管理
-
-
- 📤 导出数据
- ›
+
+
+
+