diff --git a/package-lock.json b/package-lock.json index f1b9ee7..ef8292c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2733,6 +2733,70 @@ } } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", + "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", + "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", + "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", + "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@esbuild/darwin-arm64": { "version": "0.20.2", "cpu": [ @@ -2747,6 +2811,294 @@ "node": ">=12" } }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", + "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", + "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", + "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", + "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", + "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", + "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", + "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", + "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", + "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", + "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", + "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", + "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", + "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", + "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", + "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", + "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", + "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", + "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@intlify/core-base": { "version": "9.1.9", "license": "MIT", @@ -7284,15 +7636,6 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "license": "ISC" }, - "node_modules/growly": { - "version": "1.3.0", - "resolved": "https://registry.npmmirror.com/growly/-/growly-1.3.0.tgz", - "integrity": "sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", @@ -7599,24 +7942,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmmirror.com/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz", @@ -7704,21 +8029,6 @@ "license": "MIT", "peer": true }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmmirror.com/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/isbinaryfile": { "version": "5.0.4", "resolved": "https://registry.npmmirror.com/isbinaryfile/-/isbinaryfile-5.0.4.tgz", @@ -9151,36 +9461,6 @@ "license": "MIT", "peer": true }, - "node_modules/node-notifier": { - "version": "9.0.1", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "growly": "^1.3.0", - "is-wsl": "^2.2.0", - "semver": "^7.3.2", - "shellwords": "^0.1.1", - "uuid": "^8.3.0", - "which": "^2.0.2" - } - }, - "node_modules/node-notifier/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmmirror.com/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/node-releases": { "version": "2.0.19", "resolved": "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.19.tgz", @@ -10599,15 +10879,6 @@ "node": ">=8" } }, - "node_modules/shellwords": { - "version": "0.1.1", - "resolved": "https://registry.npmmirror.com/shellwords/-/shellwords-0.1.1.tgz", - "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.1.0.tgz", @@ -11545,16 +11816,6 @@ "node": ">= 0.4.0" } }, - "node_modules/uuid": { - "version": "8.3.2", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/v8-to-istanbul": { "version": "8.1.1", "dev": true, diff --git a/src/components/app/AppNoticeBar.vue b/src/components/app/AppNoticeBar.vue new file mode 100644 index 0000000..df8ca88 --- /dev/null +++ b/src/components/app/AppNoticeBar.vue @@ -0,0 +1,78 @@ + + + + + diff --git a/src/components/app/InlineState.vue b/src/components/app/InlineState.vue new file mode 100644 index 0000000..512b2ff --- /dev/null +++ b/src/components/app/InlineState.vue @@ -0,0 +1,78 @@ + + + + + diff --git a/src/components/app/UsageDescription.vue b/src/components/app/UsageDescription.vue new file mode 100644 index 0000000..f78c2c8 --- /dev/null +++ b/src/components/app/UsageDescription.vue @@ -0,0 +1,36 @@ + + + + + diff --git a/src/components/home/HomeFeatureCard.vue b/src/components/home/HomeFeatureCard.vue new file mode 100644 index 0000000..98bf021 --- /dev/null +++ b/src/components/home/HomeFeatureCard.vue @@ -0,0 +1,194 @@ + + + + + diff --git a/src/components/home/HomeHeroCard.vue b/src/components/home/HomeHeroCard.vue new file mode 100644 index 0000000..4c3774f --- /dev/null +++ b/src/components/home/HomeHeroCard.vue @@ -0,0 +1,240 @@ + + + + + diff --git a/src/components/mail/MailCard.vue b/src/components/mail/MailCard.vue new file mode 100644 index 0000000..4788f3e --- /dev/null +++ b/src/components/mail/MailCard.vue @@ -0,0 +1,232 @@ + + + + + diff --git a/src/components/mail/MailListState.vue b/src/components/mail/MailListState.vue new file mode 100644 index 0000000..70af098 --- /dev/null +++ b/src/components/mail/MailListState.vue @@ -0,0 +1,159 @@ + + + + + diff --git a/src/components/planning/PlanCard.vue b/src/components/planning/PlanCard.vue new file mode 100644 index 0000000..492135f --- /dev/null +++ b/src/components/planning/PlanCard.vue @@ -0,0 +1,187 @@ + + + + + diff --git a/src/components/profile/ProfileHeader.vue b/src/components/profile/ProfileHeader.vue new file mode 100644 index 0000000..f7d5761 --- /dev/null +++ b/src/components/profile/ProfileHeader.vue @@ -0,0 +1,107 @@ + + + + + diff --git a/src/components/profile/ProfileMenuSection.vue b/src/components/profile/ProfileMenuSection.vue new file mode 100644 index 0000000..c1de679 --- /dev/null +++ b/src/components/profile/ProfileMenuSection.vue @@ -0,0 +1,82 @@ + + + + + diff --git a/src/components/reply/ReplyCard.vue b/src/components/reply/ReplyCard.vue new file mode 100644 index 0000000..a418338 --- /dev/null +++ b/src/components/reply/ReplyCard.vue @@ -0,0 +1,203 @@ + + + + + diff --git a/src/config/form.ts b/src/config/form.ts new file mode 100644 index 0000000..8781f5a --- /dev/null +++ b/src/config/form.ts @@ -0,0 +1,58 @@ +export const APP_NOTICE = { + text: "B站10分日本动漫已消失,9.9分仅剩12部,这一部动漫包揽三席!", +}; + +export const MESSAGE_USAGE_TIPS = [ + "填写对方手机号码,系统将向该号码发送短信", + "可选择未来的发送时间,不选则立即发送", + "使用AI文案美化功能可自动生成不同类型的短信内容", + "短信按20字一条计费,发送前可预览效果", +]; + +export const SOCIAL_TYPE_OPTIONS = [ + { text: "手机短信", value: 1, inputType: "number" }, + { text: "微信", value: 2, inputType: "text" }, + { text: "QQ", value: 3, inputType: "number" }, + { text: "钉钉", value: 4, inputType: "text" }, + { text: "企业微信", value: 5, inputType: "text" }, + { text: "其他", value: 6, inputType: "text" }, +]; + +export const MESSAGE_TEMPLATES = [ + { + typeId: 1, + type: "表白", + desc: "表达喜欢和心意,语气真诚不过度施压", + content: "有些话我想认真告诉你:遇见你以后,我开始期待每一次聊天和见面。我喜欢你,也尊重你的想法,只希望这份心意能被你看见。", + }, + { + typeId: 2, + type: "道歉", + desc: "承认问题、表达歉意,减少争辩感", + content: "对不起,之前是我没有处理好自己的情绪,也没有站在你的角度考虑。我知道一句道歉不能立刻弥补什么,但我真心希望你能看到我的歉意。", + }, + { + typeId: 3, + type: "祝福", + desc: "适合生日、纪念日和特殊日子的温柔问候", + content: "今天想把祝福送给你。愿你接下来的日子顺利、开心,也愿所有美好的事情都慢慢靠近你。", + }, + { + typeId: 4, + type: "问候", + desc: "轻量关心,不打扰也不冒犯", + content: "只是想问候你一下,希望你最近一切都好。天气变化记得照顾好自己,也希望你每天都能轻松一点。", + }, + { + typeId: 5, + type: "晚安", + desc: "适合夜晚发送,柔和表达惦记", + content: "晚安。希望你今晚能睡个好觉,把今天的疲惫都放下。明天醒来,也能拥有一点新的开心。", + }, + { + typeId: 6, + type: "思念", + desc: "表达想念,但保留体面和边界", + content: "有些时刻还是会想起你,想起我们曾经一起经历过的片段。我没有想打扰你,只是想让你知道,我依然珍惜那些回忆。", + }, +]; diff --git a/src/config/home.ts b/src/config/home.ts new file mode 100644 index 0000000..fb6d672 --- /dev/null +++ b/src/config/home.ts @@ -0,0 +1,113 @@ +import callingIcon from "@/assets/1.svg"; +import manualIcon from "@/assets/2.svg"; + +import { APP_ROUTES } from "./routes"; + +export interface HomeFeatureCardConfig { + id: number; + title: string; + description: string; + iconPath: string; + buttonText: string; + route?: string; + buttonClass?: string; + iconClass?: string; + disabledTip?: string; + tag?: string; +} + +export const HOME_HERO = { + eyebrow: "匿名短信 · 匿名电话", + title: "有些话,换一种方式认真说", + subtitle: "被拉黑、想道歉、想告白、想送祝福时,用更克制的方式把心意送达。", + highlights: ["匿名代发", "发送前预览", "定时送达"], + image: "/static/images/love.png", + actionText: "写一条匿名短信", + actionRoute: APP_ROUTES.sending, + secondaryText: "人工传话", + secondaryRoute: APP_ROUTES.manual, +}; + +export const HOME_PRIMARY_FEATURES: HomeFeatureCardConfig[] = [ + { + id: 1, + title: "人工传话", + description: "真人协助传达,更适合认真道歉和重要告白", + iconPath: manualIcon, + buttonText: "去传话", + route: APP_ROUTES.manual, + iconClass: "icon-wrapper-orange", + buttonClass: "color-button", + tag: "更有温度", + }, + { + id: 2, + title: "匿名电话", + description: "适合紧急和解、重要解释,先确认意愿再沟通", + iconPath: callingIcon, + buttonText: "去拨打", + route: APP_ROUTES.calling, + iconClass: "icon-wrapper-blue", + buttonClass: "color-button", + disabledTip: "此通道正在维护中,暂时禁用!", + tag: "即将开放", + }, +]; + +export const HOME_ADDITIONAL_FEATURES: HomeFeatureCardConfig[] = [ + { + id: 3, + title: "定时短信", + description: "生日、纪念日、晚安问候可提前设置", + iconPath: "/static/images/cat.png", + buttonText: "去设置", + route: APP_ROUTES.planning, + tag: "不怕错过", + }, + { + id: 4, + title: "AI文案美化", + description: "把冲动的话改得更真诚、更体面", + iconPath: "/static/images/cat.png", + buttonText: "去优化", + route: APP_ROUTES.sending, + tag: "降低冒犯", + }, + { + id: 5, + title: "收到回复", + description: "回复统一收进信箱,避免错过对方回应", + iconPath: "/static/images/cat.png", + buttonText: "去查看", + route: APP_ROUTES.reply, + tag: "及时查看", + }, +]; + +export const HOME_FEATURE_STYLE_CLASSES = { + icon: ["icon-wrapper-green", "icon-wrapper-purple", "icon-wrapper-red"], + button: ["green-button", "purple-button", "red-button"], +}; + +export const HOME_SCENARIOS = [ + { + title: "被拉黑后道歉", + description: "把重点放在承担责任,不反复打扰。", + }, + { + title: "鼓起勇气告白", + description: "先表达心意,给对方留出选择空间。", + }, + { + title: "生日和纪念日祝福", + description: "定时发送,适合不方便直接联系的时刻。", + }, +]; + +export const HOME_STEPS = [ + "选择短信、人工传话或电话", + "填写联系人和想说的话", + "预览确认后再发送", +]; + +export const HOME_GUARDRAILS = ["尊重对方意愿", "不鼓励频繁打扰", "内容发送前可检查"]; diff --git a/src/config/mail.ts b/src/config/mail.ts new file mode 100644 index 0000000..34dd125 --- /dev/null +++ b/src/config/mail.ts @@ -0,0 +1,104 @@ +import emptyImage from "@/assets/nodata.svg"; + +export enum MailStatus { + PENDING = 0, + SENT = 1, + FAILED = 2, +} + +export interface Mail { + id: number; + orderNumber: string; + recipient: string; + content: string; + sendTime: string; + submitTime: string; + status: MailStatus; + price: number; + isNew: boolean; +} + +export const MAIL_DETAIL_PAGE = "/pages/mailbox/detail"; + +export const MAIL_TABS = [ + { name: "全部" }, + { name: "待发送" }, + { name: "已发送" }, + { name: "发送失败" }, +]; + +export const MAIL_EMPTY_IMAGE = emptyImage; + +export const MAIL_STATUS_META: Record = { + [MailStatus.PENDING]: { + text: "待发送", + className: "status-pending", + }, + [MailStatus.SENT]: { + text: "已发送", + className: "status-sent", + }, + [MailStatus.FAILED]: { + text: "发送失败", + className: "status-failed", + }, +}; + +export const MOCK_MAIL_CONTENTS = [ + "有些话想认真说一次,不打扰你,只希望你知道我的歉意。", + "之前没有照顾好你的感受,对不起。愿你之后都能轻松一点。", + "如果还有机会,我想把没说好的话认真补上。", + "这条短信只是想把心意说清楚,不给你压力。", +]; + +export const MOCK_PHONE_PREFIXES = ["135", "136", "138", "151", "166", "171", "188", "199"]; + +export const maskRecipient = (recipient: string): string => { + if (!recipient) return ""; + + const value = String(recipient).trim(); + + if (value.length <= 7) { + return value.replace(/^(.{2}).*(.{1})$/, "$1****$2"); + } + + return `${value.slice(0, 3)}****${value.slice(-4)}`; +}; + +export const formatMailTime = (timeString: string): string => { + if (!timeString || typeof timeString !== "string") { + return String(timeString || ""); + } + + const date = new Date(timeString.replace(" ", "T")); + + if (Number.isNaN(date.getTime())) { + return timeString; + } + + const now = new Date(); + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, "0"); + const day = String(date.getDate()).padStart(2, "0"); + const hours = String(date.getHours()).padStart(2, "0"); + const minutes = String(date.getMinutes()).padStart(2, "0"); + + if (year === now.getFullYear()) { + return `${month}月${day}日 ${hours}:${minutes}`; + } + + return `${year}年${month}月${day}日 ${hours}:${minutes}`; +}; + +export const serializeMail = (mail: Mail): string => encodeURIComponent(JSON.stringify(mail)); + +export const deserializeMail = (payload?: string): Mail | null => { + if (!payload) return null; + + try { + return JSON.parse(decodeURIComponent(payload)) as Mail; + } catch (error) { + console.error("解析短信详情失败", error); + return null; + } +}; diff --git a/src/config/planning.ts b/src/config/planning.ts new file mode 100644 index 0000000..2c7e9c8 --- /dev/null +++ b/src/config/planning.ts @@ -0,0 +1,143 @@ +import { SOCIAL_TYPE_OPTIONS } from "@/config/form"; +import { maskRecipient } from "@/config/mail"; + +export type PlanCycleType = "daily" | "weekly" | "monthly"; +export type PlanStatus = "inProgress" | "completed" | "paused"; + +export interface PlanCycleOption { + type: PlanCycleType; + name: string; + desc: string; +} + +export interface PlanSubmitPayload { + cycleType: PlanCycleType; + cycleName: string; + socialType: number; + socialTypeName: string; + socialAccount: string; + content: string; +} + +export interface PlanItem { + id: string; + cycleType: PlanCycleType; + cycleName: string; + socialTypeName: string; + socialAccount: string; + content: string; + nextRunTime: string; + createdAt: string; + status: PlanStatus; +} + +export const PLAN_CYCLE_OPTIONS: PlanCycleOption[] = [ + { + type: "daily", + name: "每天", + desc: "每天定时传达一次", + }, + { + type: "weekly", + name: "每周", + desc: "每周固定传达一次", + }, + { + type: "monthly", + name: "每月", + desc: "每月固定传达一次", + }, +]; + +export const PLAN_STATUS_TABS = [ + { name: "全部", value: "all" }, + { name: "进行中", value: "inProgress" }, + { name: "已完成", value: "completed" }, +] as const; + +export const PLAN_STATUS_META: Record = { + inProgress: { + text: "进行中", + className: "status-running", + }, + completed: { + text: "已完成", + className: "status-done", + }, + paused: { + text: "已暂停", + className: "status-paused", + }, +}; + +export const PLAN_SOCIAL_OPTIONS = SOCIAL_TYPE_OPTIONS.filter((item) => item.value !== 6); + +export const MOCK_PLAN_LIST: PlanItem[] = [ + { + id: "PL250503001", + cycleType: "daily", + cycleName: "每天", + socialTypeName: "手机短信", + socialAccount: "19878384602", + content: "每天都想轻轻问候你一下,希望你今天也能顺利一点。", + nextRunTime: "2026-05-04 20:00:00", + createdAt: "2026-05-03 18:30:00", + status: "inProgress", + }, + { + id: "PL250502002", + cycleType: "weekly", + cycleName: "每周", + socialTypeName: "微信", + socialAccount: "moonlight_520", + content: "每周给你留一句温柔的话,不催促,只表达我的在意。", + nextRunTime: "2026-05-09 21:00:00", + createdAt: "2026-05-02 21:12:00", + status: "inProgress", + }, + { + id: "PL250501003", + cycleType: "monthly", + cycleName: "每月", + socialTypeName: "QQ", + socialAccount: "1289045216", + content: "这个月也想认真祝你平安顺利,愿你越来越轻松。", + nextRunTime: "2026-06-01 09:30:00", + createdAt: "2026-05-01 09:18:00", + status: "inProgress", + }, + { + id: "PL250430004", + cycleType: "daily", + cycleName: "每天", + socialTypeName: "手机短信", + socialAccount: "13677268104", + content: "晚安,愿你今晚能睡得安心一点。", + nextRunTime: "2026-04-30 23:00:00", + createdAt: "2026-04-28 22:10:00", + status: "completed", + }, + { + id: "PL250428005", + cycleType: "weekly", + cycleName: "每周", + socialTypeName: "企业微信", + socialAccount: "yanxi_2026", + content: "想把没说好的话慢慢说清楚,也尊重你的节奏。", + nextRunTime: "2026-05-05 19:30:00", + createdAt: "2026-04-28 16:02:00", + status: "paused", + }, +]; + +export const maskSocialAccount = (account: string): string => { + if (/^1\d{10}$/.test(account)) { + return maskRecipient(account); + } + + if (account.length <= 6) { + return account; + } + + return `${account.slice(0, 3)}***${account.slice(-3)}`; +}; diff --git a/src/config/profile.ts b/src/config/profile.ts new file mode 100644 index 0000000..56336c5 --- /dev/null +++ b/src/config/profile.ts @@ -0,0 +1,77 @@ +import { APP_ROUTES } from "./routes"; + +export const PROFILE_INFO = { + avatar: "/static/images/cat.png", + username: "GT-呆河马", + userId: "10086", +}; + +export const PROFILE_STATS = [ + { + label: "可用余额", + value: "¥26.80", + }, + { + label: "收到回复", + value: "2", + route: APP_ROUTES.reply, + }, + { + label: "执行计划", + value: "3", + route: APP_ROUTES.planned, + }, +] as const; + +export const PROFILE_QUICK_ACTIONS = [ + { + title: "发匿名短信", + desc: "快速写一条短信", + icon: "信", + route: APP_ROUTES.sending, + }, + { + title: "人工传话", + desc: "更柔和地表达", + icon: "传", + route: APP_ROUTES.manual, + }, + { + title: "创建计划", + desc: "定期传达心意", + icon: "计", + route: APP_ROUTES.planning, + }, + { + title: "我的信箱", + desc: "查看发送记录", + icon: "箱", + route: APP_ROUTES.mailbox, + }, +] as const; + +export const PROFILE_MENU_GROUPS = [ + [ + { + label: "隐私与安全", + action: "privacy", + }, + { + label: "使用须知", + action: "notice", + }, + { + label: "联系我们", + action: "copyWechat", + }, + ], +] as const; + +export const CONTACT_CONFIG = { + wechatId: "I18888", + copySuccessText: "微信号已复制", + copyFailText: "复制失败,请重试", +}; + +export const PROFILE_NOTICE_TEXT = "请真诚表达,避免频繁打扰对方。"; +export const PROFILE_PRIVACY_TEXT = "平台会保护你的提交信息,仅用于完成传话服务。"; diff --git a/src/config/reply.ts b/src/config/reply.ts new file mode 100644 index 0000000..3173d78 --- /dev/null +++ b/src/config/reply.ts @@ -0,0 +1,101 @@ +export interface ReplyItem { + id: string; + contactPhone: string; + originalMessage: string; + replyMessage: string; + replyTime: string; + source: "sms" | "manual"; + unread: boolean; +} + +export const REPLY_PAGE_SIZE = 6; + +export const REPLY_SOURCE_META: Record = { + sms: { + text: "短信回复", + className: "source-sms", + }, + manual: { + text: "人工传话", + className: "source-manual", + }, +}; + +export const MOCK_REPLY_LIST: ReplyItem[] = [ + { + id: "RP250503001", + contactPhone: "19878384602", + originalMessage: "有些话想认真说一次,不打扰你,只希望你知道我的歉意。", + replyMessage: "我收到了。谢谢你愿意认真说这些,我需要一点时间想想。", + replyTime: "2026-05-03 20:12:00", + source: "sms", + unread: true, + }, + { + id: "RP250503002", + contactPhone: "13993621665", + originalMessage: "之前没有照顾好你的感受,对不起。愿你之后都能轻松一点。", + replyMessage: "我已经看到了,也希望你之后能真的慢慢变好。", + replyTime: "2026-05-03 18:35:00", + source: "manual", + unread: true, + }, + { + id: "RP250502003", + contactPhone: "18826830915", + originalMessage: "如果还有机会,我想把没说好的话认真补上。", + replyMessage: "先不用急着见面,等彼此都平静一点再说吧。", + replyTime: "2026-05-02 21:08:00", + source: "sms", + unread: false, + }, + { + id: "RP250501004", + contactPhone: "15188340219", + originalMessage: "这条短信只是想把心意说清楚,不给你压力。", + replyMessage: "谢谢你的祝福,我也希望我们都能好好生活。", + replyTime: "2026-05-01 09:46:00", + source: "sms", + unread: false, + }, + { + id: "RP250430005", + contactPhone: "13677268104", + originalMessage: "对不起,之前的争吵我也有很多没有处理好的地方。", + replyMessage: "我知道了。过去的事情先放一放吧,别再互相消耗了。", + replyTime: "2026-04-30 22:20:00", + source: "manual", + unread: false, + }, + { + id: "RP250429006", + contactPhone: "19945201866", + originalMessage: "想把晚安认真补给你,也想把歉意说清楚。", + replyMessage: "晚安。也祝你以后能遇到更好的自己。", + replyTime: "2026-04-29 23:17:00", + source: "sms", + unread: false, + }, + { + id: "RP250428007", + contactPhone: "16690438152", + originalMessage: "我不会再频繁打扰,只是想最后认真表达一次。", + replyMessage: "收到。谢谢你尊重我的节奏。", + replyTime: "2026-04-28 16:02:00", + source: "manual", + unread: false, + }, +]; + +export const serializeReply = (reply: ReplyItem): string => encodeURIComponent(JSON.stringify(reply)); + +export const deserializeReply = (payload?: string): ReplyItem | null => { + if (!payload) return null; + + try { + return JSON.parse(decodeURIComponent(payload)) as ReplyItem; + } catch (error) { + console.error("解析回复详情失败", error); + return null; + } +}; diff --git a/src/config/routes.ts b/src/config/routes.ts new file mode 100644 index 0000000..22ab7ef --- /dev/null +++ b/src/config/routes.ts @@ -0,0 +1,32 @@ +export const APP_ROUTES = { + home: "/pages/index/index", + mailbox: "/pages/mailbox/index", + mine: "/pages/mine/index", + sending: "/pages/sending/index", + manual: "/pages/manual/index", + calling: "/pages/calling/index", + planning: "/pages/planning/index", + planned: "/pages/planning/planned", + reply: "/pages/reply/index", +} as const; + +export const TAB_BAR_ITEMS = [ + { + pagePath: "pages/index/index", + text: "写信", + iconPath: "static/images/send.png", + selectedIconPath: "static/images/send-active.png", + }, + { + pagePath: "pages/mailbox/index", + text: "信箱", + iconPath: "static/images/mailbox.png", + selectedIconPath: "static/images/mailbox-active.png", + }, + { + pagePath: "pages/mine/index", + text: "我的", + iconPath: "static/images/mine.png", + selectedIconPath: "static/images/mine-active.png", + }, +] as const; diff --git a/src/pages.json b/src/pages.json index 7c62524..541e66b 100644 --- a/src/pages.json +++ b/src/pages.json @@ -35,6 +35,19 @@ } } }, + { + "path": "pages/mailbox/detail", + "style": { + // #ifdef H5 + "titleNView": false, + // #endif + "navigationBarTitleText": "短信详情", + "mp-alipay": { + "titleBarColor": "#FFFFFF", + "titleColor": "#000000" + } + } + }, { "path": "pages/mine/index", "style": { @@ -113,6 +126,19 @@ } } }, + { + "path": "pages/reply/detail", + "style": { + // #ifdef H5 + "titleNView": false, + // #endif + "navigationBarTitleText": "回复详情", + "mp-alipay": { + "titleBarColor": "#FFFFFF", + "titleColor": "#000000" + } + } + }, { "path": "pages/planning/planned", "style": { @@ -134,10 +160,14 @@ "backgroundColor": "#F8F8F8" }, "tabBar": { - "color": "#999", - "selectedColor": "#00c853", + "color": "#7a7f87", + "selectedColor": "#18b566", "backgroundColor": "#ffffff", - "borderStyle": "white", + "borderStyle": "black", + "height": "56px", + "fontSize": "12px", + "iconWidth": "24px", + "spacing": "4px", "list": [ { "pagePath": "pages/index/index", diff --git a/src/pages/index/index.vue b/src/pages/index/index.vue index d826273..2a47712 100644 --- a/src/pages/index/index.vue +++ b/src/pages/index/index.vue @@ -1,334 +1,343 @@ - - \ No newline at end of file + +.step-text { + display: block; + margin-top: 18rpx; + color: #3a4354; + font-size: 24rpx; + line-height: 1.45; +} + +.additional-cards { + margin-top: 32rpx; +} + +.guardrail-bar { + display: flex; + flex-wrap: wrap; + margin-top: 24rpx; + padding: 18rpx 20rpx; + border-radius: 24rpx; + background: rgba(255, 255, 255, 0.66); + border: 1rpx solid rgba(255, 255, 255, 0.82); + box-shadow: 0 8rpx 22rpx rgba(83, 96, 130, 0.05); +} + +.guardrail-item { + color: #7b8493; + font-size: 22rpx; + line-height: 1.3; + margin-right: 20rpx; + margin-bottom: 6rpx; +} + diff --git a/src/pages/mailbox/detail.vue b/src/pages/mailbox/detail.vue new file mode 100644 index 0000000..56a6b48 --- /dev/null +++ b/src/pages/mailbox/detail.vue @@ -0,0 +1,475 @@ + + + + + diff --git a/src/pages/mailbox/index.vue b/src/pages/mailbox/index.vue index dd6a668..176ff0a 100644 --- a/src/pages/mailbox/index.vue +++ b/src/pages/mailbox/index.vue @@ -1,22 +1,33 @@ - - \ No newline at end of file + diff --git a/src/pages/manual/index.vue b/src/pages/manual/index.vue index dacd6c7..66a2039 100644 --- a/src/pages/manual/index.vue +++ b/src/pages/manual/index.vue @@ -1,469 +1,543 @@