This commit is contained in:
Felix
2025-12-12 19:45:50 +08:00
parent 9df2e00e80
commit d293a334e4
17 changed files with 329 additions and 68 deletions

View File

@@ -1672,9 +1672,9 @@ Page<IPageData, IPageInstance>({
computeDynamicLayout() {
try {
const si = wx.getSystemInfoSync()
const wh = si.windowHeight
const ww = si.windowWidth
const windowInfo = wx.getWindowInfo();
const wh = windowInfo.windowHeight
const ww = windowInfo.windowWidth
const rpx = ww / 750
const isTall = (wh / ww) > 1.8
const ratio = isTall ? 0.6 : 0.52

View File

@@ -14,7 +14,7 @@
<view class="sentence-content">
<view class="sentence-wrapper {{selectedSentenceIndex === index ? 'selected' : ''}}" wx:for="{{processedSentences}}" wx:key="index" data-index="{{index}}" bindtap="handleSentenceSelect">
<view class="sentence-content-wrapper">
<view class="word-wrapper" wx:for="{{item.words}}" wx:for-item="word" wx:for-index="windex" wx:key="windex">
<view class="word-wrapper" wx:for="{{item.words}}" wx:for-item="word" wx:for-index="windex" wx:key="windex" style="{{windex === 0 ? 'text-transform: capitalize;' : ''}}">
<span class="sentence-text" data-word="{{word}}" data-index="{{index}}" catchtap="handleWordClick">
{{word}}
</span>
@@ -28,6 +28,7 @@
<span>{{item.zh}}</span>
</view>
</view>
<view class="sentence-tips">上述内容由AI生成</view>
</view>
</view>
</view>

View File

@@ -52,7 +52,7 @@
display: flex;
flex-direction: column;
min-height: calc(100vh - 50vh);
padding-bottom: calc(0px + env(safe-area-inset-bottom));
/* padding-bottom: calc(0px + env(safe-area-inset-bottom)); */
background: #ffffff;
margin-top: calc(50vh - 40rpx);
border-top-left-radius: 24rpx;
@@ -64,13 +64,13 @@
.sentence-handle {
position: absolute;
top: 12rpx;
top: 20rpx;
left: 50%;
transform: translateX(-50%);
width: 120rpx;
height: 8rpx;
height: 10rpx;
border-radius: 16rpx;
background: #dddddd;
background: #cccccc;
box-shadow: 0 0 12rpx rgba(0,0,0,0.12);
}
@@ -78,7 +78,7 @@
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 30rpx;
margin-top: 50rpx;
}
.arrow-btn {
@@ -131,6 +131,15 @@
color: #666;
}
.sentence-tips {
font-size: 24rpx;
color: #dddddd;
position: absolute;
left: 50%;
bottom: 0%;
transform: translate(-50%, 50rpx);
}
.word-wrapper {
display: flex;
flex-direction: column;

View File

@@ -3,6 +3,8 @@
"navigationBarBackgroundColor": "#ffffff",
"backgroundColor": "#f8f9fa",
"backgroundTextStyle": "light",
"usingComponents": {},
"usingComponents": {
"t-icon": "tdesign-miniprogram/icon/icon"
},
"navigationBarTitleText": "积分"
}

View File

@@ -2,9 +2,12 @@ import apiManager from '../../utils/api'
Page({
data: {
products: [] as Array<any>
products: [] as Array<any>,
userPoints: 0,
displayUserPoints: '0',
vipLevel: 0
},
async onLoad() {
async onLoad(options: Record<string, string>) {
console.log('Coupon page loaded')
try {
const list = await apiManager.getProductList()
@@ -12,7 +15,20 @@ Page({
...p,
amountYuan: ((p.amount_cents || 0) / 100).toFixed(2)
}))
this.setData({ products })
const ptsStr = options?.points || '0'
const lvlStr = options?.vipLevel || '0'
const ptsNum = Number(ptsStr) || 0
const lvlNum = Number(lvlStr) || 0
const fmt = (n: number) => {
const s = Math.floor(n).toString()
return s.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
}
this.setData({
products,
userPoints: ptsNum,
displayUserPoints: fmt(ptsNum),
vipLevel: lvlNum
})
} catch (err) {
console.error('加载产品列表失败', err)
wx.showToast({ title: '加载失败', icon: 'none' })

View File

@@ -1,10 +1,40 @@
<!--coupon.wxml-->
<view class="coupon-container">
<!-- <view class="points_box">
<view class="points-title">
<t-icon class="points-label" name="filter-3" size="28rpx"></t-icon>
当前积分
</view>
<view class="points-row">
<view class="points-value">{{displayUserPoints}}</view>
</view>
<view class="vip-pill" wx:if="{{vipLevel > 0}}">
<text class="vip-star">★</text>
<text class="vip-text">VIP Member Level {{vipLevel}}</text>
</view>
<view class="vip-pill" wx:else>
<text class="vip-star">★</text>
<text class="vip-text">Member</text>
</view>
</view> -->
<view class="coupon_title">
获取更多积分
</view>
<view class='coupon_box {{item.one_time ? "one_time" : ""}}' wx:for="{{products}}" wx:key="id" wx:for-item="item">
<view class='content' bindtap="handleCouponTap" data-id="{{item.id}}">
<view class='content' bindtap="handleCouponTap" data-id="{{item.id}}" data-points="{{item.points}}">
<view class='title'>{{item.title}}</view>
<view class='how_much'>{{item.points}}</view>
</view>
<view class='btn'> ¥{{item.amountYuan}}</view>
</view>
<view class="tips_box">
<view class="tips-header">
<view class="tips-icon"><t-icon name="info-circle" size="32rpx"></t-icon></view>
<view class="tips-title">积分说明</view>
</view>
<view class="tips-list">
<view class="tips-item">积分购买后永久有效。</view>
<!-- <view class="tips-item"></view> -->
</view>
</view>
</view>

View File

@@ -6,23 +6,169 @@
align-content: start;
flex-wrap: wrap;
height: 100%;
padding: 0;
padding: 0 32rpx;
background-color: #f5f5f5;
}
.coupon_box{
background: linear-gradient(to right, #3e9eff, #5cbffc);
width: 40%;
border-radius: 12rpx;
text-align: center;
color: #fff;
font-family: 'Tahoma', sans-serif;
.tips_box {
margin: 32rpx 2%;
padding: 28rpx;
background: #ffffff;
border-radius: 28rpx;
box-shadow: 0 12rpx 32rpx rgba(0, 0, 0, 0.06);
position: relative;
margin: 5% 5% 0 5%;
width: 100%;
}
.tips-header {
display: flex;
align-items: center;
gap: 12rpx;
margin-bottom: 18rpx;
}
.tips-icon {
width: 40rpx;
height: 40rpx;
display: flex;
align-items: center;
justify-content: center;
}
.tips-title {
font-size: 30rpx;
font-weight: 700;
color: #333c4f;
}
.tips-list {
display: flex;
flex-direction: column;
gap: 16rpx;
}
.tips-item {
position: relative;
padding-left: 24rpx;
font-size: 26rpx;
color: #4b5565;
line-height: 38rpx;
}
.points_box {
width: 100%;
margin: 40rpx 2%;
padding: 36rpx 24rpx;
border-radius: 32rpx;
background: linear-gradient(135deg, #6a5af9 0%, #a855f7 60%, #9333ea 100%);
box-shadow: 0 12rpx 30rpx rgba(123, 67, 255, 0.35);
position: relative;
color: #ffffff;
}
.points_box::before,
.points_box::after {
content: '';
position: absolute;
width: 240rpx;
height: 240rpx;
border-radius: 50%;
filter: blur(12rpx);
pointer-events: none;
}
.points_box::before {
bottom: -80rpx;
left: -80rpx;
background: radial-gradient(closest-side, rgba(255,255,255,0.20), rgba(255,255,255,0));
}
.points_box::after {
top: -80rpx;
right: -80rpx;
background: radial-gradient(closest-side, rgba(255,255,255,0.16), rgba(255,255,255,0));
}
.points-title {
font-size: 26rpx;
opacity: 0.92;
display: flex;
align-items: center;
gap: 10rpx;
}
.points-title .points-label {
display: inline-flex;
align-items: center;
}
.points-row {
display: flex;
align-items: baseline;
gap: 16rpx;
margin-top: 24rpx;
}
.points-value {
font-size: 96rpx;
line-height: 96rpx;
font-weight: 800;
text-shadow: 0 8rpx 22rpx rgba(0,0,0,0.18);
}
.points-label {
font-size: 28rpx;
opacity: 0.9;
}
.vip-pill {
margin-top: 18rpx;
display: inline-flex;
align-items: center;
gap: 12rpx;
padding: 14rpx 22rpx;
border-radius: 999rpx;
background: rgba(255,255,255,0.18);
box-shadow: inset 0 0 0 2rpx rgba(255,255,255,0.15);
}
.vip-star {
font-size: 24rpx;
}
.vip-text {
font-size: 26rpx;
}
.coupon_title {
width: 100%;
padding: 0 2%;
font-weight: 700;
}
.coupon_box{
background: linear-gradient(to right, #5da0f9, #3071ee);
width: 46%;
border-radius: 32rpx;
text-align: center;
font-weight: 700;
color: #fff;
position: relative;
margin: 4% 2% 0 2%;
}
.coupon_box.one_time{
background: linear-gradient(to right, #FF4B2B, #FF416C);
background: linear-gradient(to right, #f96b81, #e62f54);
}
.btn{
font-size: 36rpx;
height: 80rpx;
line-height: 80rpx;
border-radius: 0 0 32rpx 32rpx;
background: linear-gradient(to right, #3c79da, #245dd4);
}
.one_time .btn{
background: linear-gradient(to right, #d74660, #cb1e44);
}
.coupon_box::before{
@@ -56,21 +202,22 @@ background: linear-gradient(to right, #3e9eff, #5cbffc);
}
.how_much{
font-size: 80rpx;
font-size: 88rpx;
text-shadow: 0 0 20rpx rgba(0,0,0,0.3); text-align: center
}
.content{
padding: 4rpx 0 32rpx 0;
border-bottom: 4rpx dashed rgba(0,0,0,0.15);
padding: 8rpx 0 20rpx 0;
border-bottom: 4rpx dashed rgba(255, 255, 255, 0.25);
position: relative;
}
.content::before{
content: '100';
content: attr(data-points);
position: absolute;
color: rgba(255,255,255,0.15);
top: 0%;
left: 16rpx;
font-size: 144rpx;
top: -7%;
transform: rotate(-15deg);
left: 2%;
font-size: 160rpx;
font-weight: bold;
}
}

View File

@@ -20,5 +20,19 @@ Page({
onUnload() {
// 页面卸载时的逻辑
},
handleEmailTap(e: any) {
const email = (e && e.currentTarget && e.currentTarget.dataset && e.currentTarget.dataset.email) ? e.currentTarget.dataset.email : 'support@blabla.team'
try {
wx.setClipboardData({
data: email,
success: () => {
wx.showToast({ title: '邮箱已复制', icon: 'none' })
}
})
} catch (err) {
wx.showToast({ title: '复制失败', icon: 'none' })
}
}
})
})

View File

@@ -4,18 +4,17 @@
<text class="title">隐私政策</text>
<view class="section">
<text class="subtitle">生效日期:【请填写发布日期】</text>
<text class="subtitle">生效日期:2025.12.12</text>
</view>
<view class="section">
<text class="subtitle">引言</text>
<text class="paragraph">blabla以下简称"我们")深知个人信息对您的重要性,并承诺按照法律法规的要求保护您的隐私安全。本《隐私政策》(以下简称"本政策")旨在向您清晰说明我们在您使用本小程序过程中如何收集、使用、存储、共享和保护您的个人信息,以及您享有的权利。</text>
<text class="paragraph">blabla以下简称"我们")深知个人信息对您的重要性,并承诺按照法律法规的要求保护您的隐私安全。本《隐私政策》(以下简称"本政策")旨在向您清晰说明我们在您使用本服务过程中如何收集、使用、存储、共享和保护您的个人信息,以及您享有的权利。</text>
</view>
<view class="section">
<text class="subtitle">1. 我们收集的信息</text>
<text class="paragraph">为向您提供核心功能,我们会收集以下类型的信息:</text>
<text class="paragraph">微信身份标识信息:当您使用微信登录时,我们会获取您的微信 OpenID。这是我们识别您身份的必要信息。</text>
<text class="paragraph">您上传的图片信息:您主动选择并上传的用于识别的图片。请注意,请勿上传包含个人隐私、他人肖像、敏感信息的图片。</text>
<text class="paragraph">您上传的语音信息:如果您使用发音评测功能,我们会收集并处理您的语音录音。</text>
<text class="paragraph">设备与日志信息为保障服务安全运行我们会自动收集设备型号、操作系统版本、IP地址、访问时间、错误日志等信息。</text>
@@ -44,9 +43,9 @@
<view class="section">
<text class="subtitle">5. 您的权利</text>
<text class="paragraph">您对自己的个人信息享有以下权利:</text>
<text class="paragraph">访问与更正:您有权访问我们持有的关于您的个人信息。由于我们仅存储微信OpenID您可以通过微信个人资料设置修改您的头像和昵称。</text>
<text class="paragraph">删除与撤回同意:您可以通过小程序内'联系客服-申请注销账户'的方式,要求删除您的账户信息。您也可以在设备系统设置中关闭相机、麦克风权限来撤回相应授权。</text>
<text class="paragraph">您对自己的数据享有以下权利:</text>
<text class="paragraph">访问:您有权访问我们持有的关于您的所有数据。</text>
<text class="paragraph">删除与撤回同意:您可以通过本政策提供的联系方式,要求删除您的账户信息。您也可以在设备系统设置中关闭相机、麦克风权限来撤回相应授权。</text>
<text class="paragraph">投诉与举报:如果您认为我们的处理行为侵害了您的权益,您可以通过本政策提供的联系方式向我们投诉,或向相关监管部门举报。</text>
</view>
@@ -67,9 +66,9 @@
<view class="section">
<text class="subtitle">9. 联系我们</text>
<text class="paragraph">如您对本政策有任何疑问、意见或需要行使权利,请通过以下方式与我们联系:</text>
<text class="paragraph">【请填写负责数据保护的联系方式DPO@yourcompany.com】</text>
<text class="paragraph">我们将在收到请求后的15个工作日内予以回复和处理。</text>
<text class="paragraph">如您对本政策有任何疑问、意见或需要行使权利,请通过以下邮箱与我们联系:</text>
<view class="paragraph email" bindtap="handleEmailTap" bindlongpress="handleEmailTap" data-email="support@blabla.team">support@blabla.team</view>
<text class="paragraph">我们将在收到请求后尽快予以回复和处理。</text>
</view>
</view>
</view>
</view>

View File

@@ -39,4 +39,9 @@
color: #594a4e;
line-height: 40rpx;
display: block;
}
}
.email {
color: #2563eb;
text-decoration: underline;
}

View File

@@ -103,6 +103,10 @@ Page({
async initPage() {
try {
console.log('开始初始化个人中心页面')
// wx.setNavigationBarColor({
// frontColor: '#000000',
// backgroundColor: '#F5F5F5'
// });
const startTime = Date.now()
// 先设置基础数据,避免页面空白
@@ -315,15 +319,15 @@ Page({
let details = '暂无缓存数据'
if (stats.totalSize > 0) {
const detailParts = []
if (stats.sizeByType.audio > 0) {
detailParts.push(`音频:${apiManager.formatFileSize(stats.sizeByType.audio)}`)
}
const imageTotal = (stats.sizeByType.image || 0) + (stats.sizeByType.thumbnail || 0)
// 图片和缩略图的总大小
if (imageTotal > 0) {
detailParts.push(`图片${apiManager.formatFileSize(imageTotal)}`)
detailParts.push(`文件${apiManager.formatFileSize(imageTotal)}`)
}
if (stats.sizeByType.dict > 0) {
detailParts.push(`词典:${apiManager.formatFileSize(stats.sizeByType.dict)}`)
// 音频和词典的总大小
const fileTotal = (stats.sizeByType.audio || 0) + (stats.sizeByType.dict || 0)
if (fileTotal > 0) {
detailParts.push(`数据:${apiManager.formatFileSize(fileTotal)}`)
}
details = detailParts.join('')
}

View File

@@ -69,7 +69,7 @@
maxcharacter="{{6}}"
/>
</t-dialog>
<navigator url="/pages/coupon/coupon" class="cell-navigator">
<navigator url="/pages/coupon/coupon?points={{points.balance}}" class="cell-navigator">
<t-cell title="积分" hover note="{{points.balance}}">
<t-icon slot="left-icon" name="star" size="44rpx"></t-icon>
</t-cell>

View File

@@ -20,5 +20,19 @@ Page({
onUnload() {
// 页面卸载时的逻辑
},
handleEmailTap(e: any) {
const email = (e && e.currentTarget && e.currentTarget.dataset && e.currentTarget.dataset.email) ? e.currentTarget.dataset.email : 'support@blabla.team'
try {
wx.setClipboardData({
data: email,
success: () => {
wx.showToast({ title: '邮箱已复制', icon: 'none' })
}
})
} catch (err) {
wx.showToast({ title: '复制失败', icon: 'none' })
}
}
})
})

View File

@@ -5,8 +5,12 @@
<view class="section">
<text class="subtitle">欢迎使用 blabla</text>
<text class="paragraph">本用户协议(以下简称"本协议")由您(以下简称"用户"或"您")与 blabla 小程序运营者(以下简称"我们")订立,旨在明确您在使用 blabla 微信小程序(以下简称"本小程序")时的权利与义务。</text>
<text class="paragraph">请您在使用本小程序前,仔细阅读并理解本协议及《隐私政策》 的全部内容。</text>
<text class="paragraph">本用户协议(以下简称"本协议")由您(以下简称"用户"或"您")与 blabla 小程序运营者(以下简称"我们")订立,旨在明确您在使用 blabla 服务(以下简称"本服务")时的权利与义务。</text>
<view class="paragraph">
<text>请您在使用本服务前,仔细阅读并理解本协议及</text>
<navigator url="/pages/privacy/privacy" class="link">《隐私政策》</navigator>
<text>的全部内容。</text>
</view>
</view>
<view class="section">
@@ -19,22 +23,26 @@
<view class="section">
<text class="subtitle">2. 用户行为规范</text>
<text class="paragraph">您在使用本小程序过程中不得从事以下行为:</text>
<text class="paragraph">您在使用本服务过程中不得从事以下行为:</text>
<text class="paragraph">违反法律法规、社会主义制度、社会公序良俗的行为。</text>
<text class="paragraph">上传、拍摄任何侵犯他人隐私权、肖像权、著作权、商业秘密或涉及国家秘密的内容。</text>
<text class="paragraph">试图破解、反向工程、干扰或破坏本小程序的正常运行及相关技术服务。</text>
<text class="paragraph">试图破解、反向工程、干扰或破坏本服务的正常运行及相关技术服务。</text>
<text class="paragraph">利用本服务进行任何未经授权的商业活动。</text>
<text class="paragraph">如您违反上述规定,我们有权采取限制或禁止使用服务、终止您的访问等必要措施,且不因此对您承担任何责任。</text>
</view>
<view class="section">
<text class="subtitle">3. 知识产权声明</text>
<text class="paragraph">本小程序的界面设计、标识、源代码、技术、内容除用户上传的内容及第三方AI返回的结果外的知识产权均归我们或相关权利人所有。未经我们书面许可任何单位或个人不得擅自使用、复制、修改或创建衍生作品。</text>
<text class="paragraph">本服务的界面设计、标识、源代码、技术、内容除用户上传的内容及第三方AI返回的结果外的知识产权均归我们或相关权利人所有。未经我们书面许可任何单位或个人不得擅自使用、复制、修改或创建衍生作品。</text>
</view>
<view class="section">
<text class="subtitle">4. 隐私保护</text>
<text class="paragraph">我们高度重视您的隐私。关于我们如何收集、使用、存储和保护您的个人信息(如微信标识、上传的图片、语音等),请详细阅读我们另行制定的 《隐私政策》 。</text>
<view class="paragraph">
<text>我们高度重视您的隐私。关于我们如何收集、使用、存储和保护您的个人信息(上传的图片、语音等),请详细阅读我们另行制定的</text>
<navigator url="/pages/privacy/privacy" class="link">《隐私政策》</navigator>
<text>。</text>
</view>
</view>
<view class="section">
@@ -55,13 +63,13 @@
<view class="section">
<text class="subtitle">8. 协议更新</text>
<text class="paragraph">我们可能适时修订本协议。更新后的协议将在本小程序内公示。若您继续使用服务,即视为接受更新后的协议。</text>
<text class="paragraph">我们可能适时修订本协议。更新后的协议将在本服务内公示。若您继续使用服务,即视为接受更新后的协议。</text>
</view>
<view class="section">
<text class="subtitle">9. 联系我们</text>
<text class="paragraph">如您对本协议有任何疑问、意见或建议,请通过以下方式联系我们:</text>
<text class="paragraph">【请填写有效的联系方式,如邮箱或在线客服入口】</text>
<text class="paragraph">如您对本协议有任何疑问、意见或建议,请通过以下邮箱联系我们:</text>
<view class="paragraph email" bindtap="handleEmailTap" bindlongpress="handleEmailTap" data-email="support@blabla.team">support@blabla.team</view>
</view>
</view>
</view>
</view>

View File

@@ -39,4 +39,16 @@
color: #594a4e;
line-height: 40rpx;
display: block;
}
}
.email {
color: #2563eb;
text-decoration: underline;
}
.link {
color: #2563eb;
text-decoration: underline;
display: inline-block;
}

View File

@@ -1008,8 +1008,8 @@ Page({
},
async computeWaterfallColumns(images: any[]): Promise<{ left: any[]; right: any[] }> {
const si = wx.getSystemInfoSync();
const ww = si.windowWidth;
const windowInfo = wx.getWindowInfo();
const ww = windowInfo.windowWidth;
const rpx = ww / 750;
const padPx = Math.floor(24 * rpx);
const gapPx = Math.floor(12 * rpx);
@@ -1051,8 +1051,8 @@ Page({
if (!items || items.length < 2) return;
const idx = items.findIndex((it: any) => it && it.key === this.data.selectedDateKey);
if (idx < 0) return;
const si = wx.getSystemInfoSync();
const ww = si.windowWidth;
const windowInfo = wx.getWindowInfo();
const ww = windowInfo.windowWidth;
const rpx = ww / 750;
const itemW = Math.floor(120 * rpx);
const gap = Math.floor(24 * rpx);

View File

@@ -1,5 +1,5 @@
<!-- upload.wxml - 主功能页面 -->
<navigation-bar title="" back="{{false}}" color="{{day_type === 'night' ? 'white' : 'black'}}" background="{{day_type === 'night' ? '#232946' : '#fffffe'}}">
<navigation-bar title="" back="{{false}}" color="{{day_type === 'night' ? 'white' : 'black'}}" background="{{day_type === 'night' ? '#0E1330' : '#FDFDFC'}}">
<view slot="left">
<t-icon class="user-home" name="user-circle" size="46rpx" bind:tap="goProfile" />
</view>