hookehuyr

feat: 更新页面标题和优化多个页面功能

refactor(PointsDetail): 替换按钮为视图组件并更新图标
refactor(Rewards): 添加搜索功能并优化兑换券列表样式
refactor(Feedback): 重构反馈页面布局和交互逻辑
refactor(RewardDetail): 重新设计优惠券详情页面结构
style: 删除未使用的图片资源
1 export default { 1 export default {
2 - navigationBarTitleText: '首页' 2 + navigationBarTitleText: '意见反馈'
3 } 3 }
......
1 <template> 1 <template>
2 - <view class="min-h-screen flex flex-col bg-white"> 2 + <view class="min-h-screen bg-white flex flex-col">
3 - <AppHeader title="意见反馈" /> 3 + <view class="flex-1 px-4 py-6 overflow-auto">
4 - <view class="flex-1 px-4 py-6 pb-20"> 4 + <!-- Feedback Section -->
5 - <form @submit.prevent="handleSubmit" class="space-y-6"> 5 + <view class="mb-6">
6 - <view> 6 + <view class="text-lg font-medium mb-2">您的反馈</view>
7 - <label for="feedback" class="block text-sm font-medium text-gray-700 mb-1"> 7 + <view class="bg-white rounded-lg border border-gray-200 p-4">
8 - 您的反馈
9 - </label>
10 <textarea 8 <textarea
11 - id="feedback" 9 + v-model="feedbackText"
12 - rows="5" 10 + class="w-full text-gray-600 focus:outline-none resize-none"
13 - class="w-full p-3 border border-gray-300 rounded-lg focus:ring-blue-500 focus:border-blue-500"
14 placeholder="请描述您遇到的问题或建议..." 11 placeholder="请描述您遇到的问题或建议..."
15 - v-model="feedback" 12 + :rows="4"
16 - required
17 /> 13 />
18 </view> 14 </view>
19 - <view> 15 + </view>
20 - <label class="block text-sm font-medium text-gray-700 mb-1"> 16 +
21 - 上传截图 (可选) 17 + <!-- Upload Screenshot Section -->
22 - </label> 18 + <view class="mb-6">
23 - <view class="flex flex-wrap gap-2 mb-2"> 19 + <view class="text-lg font-medium mb-2">上传截图 (可选)</view>
24 - <view v-for="(image, index) in images" :key="index" class="relative w-20 h-20"> 20 + <view v-if="screenshot" class="mb-4">
25 - <image :src="image" :alt="`上传图片 ${index + 1}`" class="w-full h-full object-cover rounded-lg" /> 21 + <view class="relative inline-block">
26 - <button type="button" class="absolute -top-2 -right-2 bg-red-500 text-white rounded-full p-1" @click="removeImage(index)"> 22 + <image
27 - <Failure size="16" /> 23 + :src="screenshot"
28 - </button> 24 + class="w-24 h-24 rounded-lg object-cover"
25 + mode="aspectFill"
26 + @tap="previewImage"
27 + />
28 + <view
29 + @click="deleteImage"
30 + class="absolute -top-2 -right-2 w-5 h-5 bg-red-500 rounded-full flex items-center justify-center"
31 + >
32 + <view class="text-white text-xs">×</view>
33 + </view>
34 + </view>
29 </view> 35 </view>
30 <view 36 <view
31 - class="w-20 h-20 flex flex-col items-center justify-center border-2 border-dashed border-gray-300 rounded-lg cursor-pointer hover:bg-gray-50" 37 + v-if="!screenshot"
38 + class="border border-dashed border-gray-300 rounded-lg p-6 flex flex-col items-center justify-center"
32 @click="chooseImage" 39 @click="chooseImage"
33 > 40 >
34 - <Upload size="24" class="text-gray-400" /> 41 + <view class="text-gray-400 mb-2">
35 - <span class="text-xs text-gray-500 mt-1">添加图片</span> 42 + <Photograph size="24" />
36 </view> 43 </view>
44 + <view class="text-center text-gray-400">添加图片</view>
37 </view> 45 </view>
38 </view> 46 </view>
39 - <view> 47 +
40 - <label for="name" class="block text-sm font-medium text-gray-700 mb-1"> 48 + <!-- Name Section -->
41 - 您的姓名 49 + <view class="mb-6">
42 - </label> 50 + <view class="text-lg font-medium mb-2">您的姓名</view>
51 + <view class="bg-white rounded-lg border border-gray-200 p-4">
43 <input 52 <input
44 type="text" 53 type="text"
45 - id="name"
46 - class="w-full p-3 border border-gray-300 rounded-lg focus:ring-blue-500 focus:border-blue-500"
47 - placeholder="请输入您的姓名"
48 v-model="name" 54 v-model="name"
55 + class="w-full text-gray-600 focus:outline-none"
56 + placeholder="请输入您的姓名"
49 /> 57 />
50 </view> 58 </view>
51 - <view> 59 + </view>
52 - <label for="contact" class="block text-sm font-medium text-gray-700 mb-1"> 60 +
53 - 联系方式 61 + <!-- Contact Section -->
54 - </label> 62 + <view class="mb-10">
63 + <view class="text-lg font-medium mb-2">联系方式</view>
64 + <view class="bg-white rounded-lg border border-gray-200 p-4">
55 <input 65 <input
56 type="text" 66 type="text"
57 - id="contact"
58 - class="w-full p-3 border border-gray-300 rounded-lg focus:ring-blue-500 focus:border-blue-500"
59 - placeholder="请输入您的手机号或微信号"
60 v-model="contact" 67 v-model="contact"
68 + class="w-full text-gray-600 focus:outline-none"
69 + placeholder="请输入您的手机号或微信号"
61 /> 70 />
62 </view> 71 </view>
63 - <button type="submit" class="w-full py-3 bg-blue-500 text-white font-medium rounded-lg hover:bg-blue-600 transition-colors"> 72 + </view>
73 +
74 + <!-- Submit Button -->
75 + <view
76 + @click="submitFeedback"
77 + class="w-full py-3 bg-blue-500 text-white text-lg font-medium rounded-lg flex items-center justify-center"
78 + >
64 提交反馈 79 提交反馈
65 - </button>
66 - </form>
67 </view> 80 </view>
68 - <BottomNav /> 81 + </view>
82 +
83 + <!-- Image Preview -->
84 + <nut-image-preview
85 + v-model:show="previewVisible"
86 + :images="previewImages"
87 + :init-no="0"
88 + @close="closePreview"
89 + />
69 </view> 90 </view>
70 </template> 91 </template>
71 92
72 <script setup> 93 <script setup>
73 import { ref } from 'vue'; 94 import { ref } from 'vue';
74 import Taro from '@tarojs/taro'; 95 import Taro from '@tarojs/taro';
75 -import AppHeader from '../../components/AppHeader.vue'; 96 +import { Photograph } from '@nutui/icons-vue-taro';
76 -import BottomNav from '../../components/BottomNav.vue';
77 -import { Upload, Failure } from '@nutui/icons-vue-taro';
78 97
79 -const feedback = ref(''); 98 +const feedbackText = ref('');
99 +const screenshot = ref('');
80 const name = ref(''); 100 const name = ref('');
81 const contact = ref(''); 101 const contact = ref('');
82 -const images = ref([]); 102 +const previewVisible = ref(false);
103 +const previewImages = ref([]);
104 +
105 +/**
106 + * 显示提示信息
107 + */
108 +const showToast = (message, type = 'success') => {
109 + const icon = type === 'error' ? 'error' : 'success';
110 + Taro.showToast({
111 + title: message,
112 + icon: icon,
113 + duration: 2000
114 + });
115 +};
83 116
117 +/**
118 + * 选择图片
119 + */
84 const chooseImage = () => { 120 const chooseImage = () => {
85 Taro.chooseImage({ 121 Taro.chooseImage({
86 - count: 9 - images.value.length, 122 + count: 1,
87 - sizeType: ['original', 'compressed'], 123 + sizeType: ['compressed'],
88 sourceType: ['album', 'camera'], 124 sourceType: ['album', 'camera'],
89 - success: (res) => { 125 + success: function (res) {
90 - images.value = [...images.value, ...res.tempFilePaths]; 126 + const tempFilePath = res.tempFilePaths[0];
127 + screenshot.value = tempFilePath;
128 + },
129 + fail: function () {
130 + showToast('选择图片失败', 'error');
91 } 131 }
92 }); 132 });
93 }; 133 };
94 134
95 -const removeImage = (index) => { 135 +/**
96 - images.value = images.value.filter((_, i) => i !== index); 136 + * 预览图片
137 + */
138 +const previewImage = () => {
139 + previewImages.value = [{ src: screenshot.value }];
140 + previewVisible.value = true;
97 }; 141 };
98 142
99 -const handleSubmit = () => { 143 +/**
100 - // In a real app, we would send this data to a server 144 + * 关闭预览
101 - Taro.showToast({ 145 + */
102 - title: '感谢您的反馈!我们会尽快处理。', 146 +const closePreview = () => {
103 - icon: 'success', 147 + previewVisible.value = false;
104 - duration: 2000 148 +};
105 - });
106 149
107 - setTimeout(() => { 150 +/**
108 - Taro.navigateBack(); 151 + * 删除图片
109 - }, 2000); 152 + */
153 +const deleteImage = () => {
154 + screenshot.value = '';
155 +};
156 +
157 +/**
158 + * 提交反馈
159 + */
160 +const submitFeedback = () => {
161 + if (!feedbackText.value) {
162 + showToast('请描述您遇到的问题或建议', 'error');
163 + return;
164 + }
165 + if (!name.value) {
166 + showToast('请输入您的姓名', 'error');
167 + return;
168 + }
169 + if (!contact.value) {
170 + showToast('请输入您的手机号或微信号', 'error');
171 + return;
172 + }
173 +
174 + // 在实际应用中,这里会处理提交逻辑,例如上传图片和发送数据到服务器
175 + showToast('提交成功');
176 +
177 + // 提交成功后清空表单
178 + feedbackText.value = '';
179 + screenshot.value = '';
180 + name.value = '';
181 + contact.value = '';
110 }; 182 };
111 </script> 183 </script>
184 +
185 +<style lang="less">
186 +// 你可以在这里添加自定义样式
187 +</style>
......
1 +/*
2 + * @Date: 2025-08-27 18:25:28
3 + * @LastEditors: hookehuyr hookehuyr@gmail.com
4 + * @LastEditTime: 2025-08-28 00:26:01
5 + * @FilePath: /lls_program/src/pages/PointsDetail/index.config.js
6 + * @Description: 文件描述
7 + */
1 export default { 8 export default {
2 - navigationBarTitleText: '首页' 9 + navigationBarTitleText: '积分明细'
3 } 10 }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
2 <view class="min-h-screen flex flex-col bg-white"> 2 <view class="min-h-screen flex flex-col bg-white">
3 <!-- Blue header background --> 3 <!-- Blue header background -->
4 <view class="bg-blue-500 h-52 absolute w-full top-0 left-0 z-0"></view> 4 <view class="bg-blue-500 h-52 absolute w-full top-0 left-0 z-0"></view>
5 - <AppHeader title="积分明细" /> 5 + <!-- <AppHeader title="积分明细" /> -->
6 <!-- Content --> 6 <!-- Content -->
7 <view class="relative z-10 flex-1 pb-20"> 7 <view class="relative z-10 flex-1 pb-20">
8 <!-- Points display --> 8 <!-- Points display -->
...@@ -14,10 +14,10 @@ ...@@ -14,10 +14,10 @@
14 <view class="bg-white rounded-t-3xl px-4 pt-5"> 14 <view class="bg-white rounded-t-3xl px-4 pt-5">
15 <view class="flex justify-between items-center mb-4"> 15 <view class="flex justify-between items-center mb-4">
16 <h3 class="text-lg font-medium">积分攻略</h3> 16 <h3 class="text-lg font-medium">积分攻略</h3>
17 - <button class="text-blue-500 text-sm flex items-center"> 17 + <view class="text-blue-500 text-sm flex items-center">
18 查看全部 18 查看全部
19 <Right size="16" /> 19 <Right size="16" />
20 - </button> 20 + </view>
21 </view> 21 </view>
22 <!-- Strategy cards --> 22 <!-- Strategy cards -->
23 <view class="space-y-3 mb-6"> 23 <view class="space-y-3 mb-6">
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
34 </view> 34 </view>
35 <view class="bg-blue-50 p-4 rounded-lg flex items-start"> 35 <view class="bg-blue-50 p-4 rounded-lg flex items-start">
36 <view class="w-10 h-10 bg-blue-100 rounded-full flex items-center justify-center mr-3"> 36 <view class="w-10 h-10 bg-blue-100 rounded-full flex items-center justify-center mr-3">
37 - <Trophy size="20" class="text-blue-500" /> 37 + <My size="20" class="text-blue-500" />
38 </view> 38 </view>
39 <view> 39 <view>
40 <h4 class="font-medium">参与周末步数挑战</h4> 40 <h4 class="font-medium">参与周末步数挑战</h4>
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
45 </view> 45 </view>
46 <view class="bg-blue-50 p-4 rounded-lg flex items-start"> 46 <view class="bg-blue-50 p-4 rounded-lg flex items-start">
47 <view class="w-10 h-10 bg-blue-100 rounded-full flex items-center justify-center mr-3"> 47 <view class="w-10 h-10 bg-blue-100 rounded-full flex items-center justify-center mr-3">
48 - <People size="20" class="text-blue-500" /> 48 + <My size="20" class="text-blue-500" />
49 </view> 49 </view>
50 <view> 50 <view>
51 <h4 class="font-medium">邀请家人加入家庭</h4> 51 <h4 class="font-medium">邀请家人加入家庭</h4>
...@@ -58,15 +58,15 @@ ...@@ -58,15 +58,15 @@
58 <!-- Tabs --> 58 <!-- Tabs -->
59 <view class="border-b border-gray-200"> 59 <view class="border-b border-gray-200">
60 <view class="flex space-x-8"> 60 <view class="flex space-x-8">
61 - <button :class="['py-3 font-medium', activeTab === 'all' ? 'text-blue-500 border-b-2 border-blue-500' : 'text-gray-500']" @click="activeTab = 'all'"> 61 + <view :class="['py-3 font-medium', activeTab === 'all' ? 'text-blue-500 border-b-2 border-blue-500' : 'text-gray-500']" @click="activeTab = 'all'">
62 全部 62 全部
63 - </button> 63 + </view>
64 - <button :class="['py-3 font-medium', activeTab === 'earned' ? 'text-blue-500 border-b-2 border-blue-500' : 'text-gray-500']" @click="activeTab = 'earned'"> 64 + <view :class="['py-3 font-medium', activeTab === 'earned' ? 'text-blue-500 border-b-2 border-blue-500' : 'text-gray-500']" @click="activeTab = 'earned'">
65 已发放 65 已发放
66 - </button> 66 + </view>
67 - <button :class="['py-3 font-medium', activeTab === 'spent' ? 'text-blue-500 border-b-2 border-blue-500' : 'text-gray-500']" @click="activeTab = 'spent'"> 67 + <view :class="['py-3 font-medium', activeTab === 'spent' ? 'text-blue-500 border-b-2 border-blue-500' : 'text-gray-500']" @click="activeTab = 'spent'">
68 已消耗 68 已消耗
69 - </button> 69 + </view>
70 </view> 70 </view>
71 </view> 71 </view>
72 <!-- Points history list --> 72 <!-- Points history list -->
...@@ -84,7 +84,7 @@ ...@@ -84,7 +84,7 @@
84 </view> 84 </view>
85 </view> 85 </view>
86 </view> 86 </view>
87 - <BottomNav /> 87 + <!-- <BottomNav /> -->
88 </view> 88 </view>
89 </template> 89 </template>
90 90
......
1 export default { 1 export default {
2 - navigationBarTitleText: '首页' 2 + navigationBarTitleText: '隐私政策'
3 } 3 }
......
1 +<!--
2 + * @Date: 2025-08-27 17:49:58
3 + * @LastEditors: hookehuyr hookehuyr@gmail.com
4 + * @LastEditTime: 2025-08-28 00:30:58
5 + * @FilePath: /lls_program/src/pages/PrivacyPolicy/index.vue
6 + * @Description: 文件描述
7 +-->
1 <template> 8 <template>
2 <view class="min-h-screen flex flex-col bg-white"> 9 <view class="min-h-screen flex flex-col bg-white">
3 - <AppHeader title="隐私政策" /> 10 + <!-- <AppHeader title="隐私政策" /> -->
4 <view class="flex-1 px-4 py-6 pb-20"> 11 <view class="flex-1 px-4 py-6 pb-20">
5 <view class="prose prose-sm max-w-none"> 12 <view class="prose prose-sm max-w-none">
6 <h2 class="text-xl font-bold mb-4">老来赛隐私政策</h2> 13 <h2 class="text-xl font-bold mb-4">老来赛隐私政策</h2>
...@@ -108,7 +115,7 @@ ...@@ -108,7 +115,7 @@
108 <p class="text-gray-700 mt-8">最后更新日期:2023年5月1日</p> 115 <p class="text-gray-700 mt-8">最后更新日期:2023年5月1日</p>
109 </view> 116 </view>
110 </view> 117 </view>
111 - <BottomNav /> 118 + <!-- <BottomNav /> -->
112 </view> 119 </view>
113 </template> 120 </template>
114 121
......
1 +/*
2 + * @Date: 2025-08-27 18:25:42
3 + * @LastEditors: hookehuyr hookehuyr@gmail.com
4 + * @LastEditTime: 2025-08-28 09:39:10
5 + * @FilePath: /lls_program/src/pages/RewardDetail/index.config.js
6 + * @Description: 文件描述
7 + */
1 export default { 8 export default {
2 - navigationBarTitleText: '首页' 9 + navigationBarTitleText: '兑换券详情'
3 } 10 }
......
1 <template> 1 <template>
2 - <view class="min-h-screen flex flex-col bg-gradient-to-br from-blue-50 to-purple-50"> 2 + <view class="min-h-screen bg-white pb-24">
3 - <AppHeader title="优惠券详情" /> 3 + <!-- <AppHeader title="优惠券详情" :showBack="true" /> -->
4 - <view class="flex-1 p-4"> 4 + <!-- Top Image -->
5 - <template v-if="!redeemed"> 5 + <view class="w-full h-48">
6 - <view class="bg-white rounded-2xl shadow-sm overflow-hidden mb-4"> 6 + <image :src="reward.image" class="w-full h-full object-cover" />
7 - <view class="h-40 bg-blue-600 flex items-center justify-center p-6">
8 - <image :src="reward.image" :alt="reward.merchant" class="max-h-full max-w-full object-contain" />
9 - </view>
10 - <view class="p-4">
11 - <h1 class="text-xl font-medium mb-1">{{ reward.title }}</h1>
12 - <p class="text-gray-600">{{ reward.description }}</p>
13 - <view class="flex items-center mt-4 text-blue-600">
14 - <Ticket size="20" class="mr-2" />
15 - <span class="font-medium">{{ reward.points }} 积分</span>
16 </view> 7 </view>
8 +
9 + <!-- Main Content -->
10 + <view class="p-6">
11 + <!-- Points and Title -->
12 + <view class="text-center mb-8">
13 + <view class="text-4xl font-bold text-blue-500 mb-2">
14 + <text class="text-2xl">{{ reward.points }} 积分</text>
17 </view> 15 </view>
16 + <h1 class="text-xl font-bold">{{ reward.title }}</h1>
18 </view> 17 </view>
19 18
20 - <GlassCard class="mb-4"> 19 + <!-- Details Sections -->
21 - <h2 class="text-lg font-medium mb-4">使用须知</h2> 20 + <view class="space-y-6">
22 - <view class="space-y-3"> 21 + <!-- Applicable Stores -->
23 - <view class="flex">
24 - <Calendar size="20" class="text-gray-500 mr-3 flex-shrink-0" />
25 <view> 22 <view>
26 - <p class="font-medium">有效期</p> 23 + <h2 class="text-lg font-medium mb-3">可用门店</h2>
27 - <p class="text-gray-600">{{ reward.validUntil }}</p> 24 + <view class="space-y-2 text-gray-600">
25 + <view v-for="store in reward.stores" :key="store" class="flex text-sm">
26 + <span class="mr-2">·</span>
27 + <p>{{ store }}</p>
28 </view> 28 </view>
29 </view> 29 </view>
30 - <view class="flex"> 30 + </view>
31 - <Location2 size="20" class="text-gray-500 mr-3 flex-shrink-0" /> 31 +
32 + <!-- Redemption Rules -->
32 <view> 33 <view>
33 - <p class="font-medium">适用门店</p> 34 + <h2 class="text-lg font-medium mb-3">兑换规则</h2>
34 - <p class="text-gray-600">{{ reward.locations }}</p> 35 + <view class="space-y-2 text-gray-600">
36 + <view v-for="rule in reward.redemption_rules" :key="rule" class="flex text-sm">
37 + <span class="mr-2">·</span>
38 + <p>{{ rule }}</p>
35 </view> 39 </view>
36 </view> 40 </view>
37 </view> 41 </view>
38 - </GlassCard>
39 42
40 - <GlassCard class="mb-6"> 43 + <!-- Usage Rules -->
41 - <h2 class="text-lg font-medium mb-4">使用条款</h2> 44 + <view>
42 - <view class="space-y-2"> 45 + <h2 class="text-lg font-medium mb-3">使用规则</h2>
43 - <view v-for="(term, index) in reward.terms" :key="index" class="flex"> 46 + <view class="space-y-2 text-gray-600">
44 - <Info size="16" class="text-gray-500 mr-2 flex-shrink-0 mt-0.5" /> 47 + <view v-for="rule in reward.usage_rules" :key="rule" class="flex text-sm">
45 - <p class="text-gray-600">{{ term }}</p> 48 + <span class="mr-2">·</span>
49 + <p>{{ rule }}</p>
50 + </view>
51 + </view>
52 + </view>
46 </view> 53 </view>
47 </view> 54 </view>
48 - </GlassCard>
49 55
50 - <PrimaryButton @click="handleRedeem" :disabled="redeeming"> 56 + <!-- Bottom Button -->
51 - <template v-if="redeeming"> 57 + <view class="fixed bottom-0 left-0 right-0 p-4 bg-white border-t border-gray-100">
52 - <view class="animate-spin mr-2"> 58 + <nut-button type="primary" size="large" block color="#3B82F6" @click="handleRedeem">
53 - <Loading class="w-5 h-5" />
54 - </view>
55 - 兑换中...
56 - </template>
57 - <template v-else>
58 立即兑换 59 立即兑换
59 - </template> 60 + </nut-button>
60 - </PrimaryButton>
61 - </template>
62 -
63 - <template v-else>
64 - <view class="flex flex-col items-center justify-center h-full">
65 - <GlassCard class="w-full max-w-md">
66 - <view class="flex flex-col items-center">
67 - <view class="w-20 h-20 bg-green-100 rounded-full flex items-center justify-center mb-4">
68 - <Check size="40" class="text-green-600" />
69 - </view>
70 - <h2 class="text-xl font-medium mb-2">兑换成功</h2>
71 - <p class="text-gray-600 text-center mb-6">
72 - 您已成功兑换{{ reward.title }}
73 - </p>
74 - <view class="bg-gray-50 w-full rounded-lg p-4 mb-6 text-center">
75 - <p class="text-gray-600 mb-2">兑换码</p>
76 - <p class="text-2xl font-mono tracking-wider font-medium">
77 - SB12345678
78 - </p>
79 - </view>
80 - <image :src="reward.image" :alt="reward.merchant" class="w-24 h-24 object-contain mb-6" />
81 - <view class="text-center mb-6">
82 - <p class="font-medium">{{ reward.title }}</p>
83 - <p class="text-gray-600">{{ reward.description }}</p>
84 - <p class="text-gray-500 text-sm mt-2">
85 - 有效期至: {{ reward.validUntil }}
86 - </p>
87 - </view>
88 - <PrimaryButton @click="goBack">
89 - 返回兑换页面
90 - </PrimaryButton>
91 - </view>
92 - </GlassCard>
93 - </view>
94 - </template>
95 </view> 61 </view>
96 </view> 62 </view>
97 </template> 63 </template>
...@@ -100,37 +66,58 @@ ...@@ -100,37 +66,58 @@
100 import { ref } from 'vue'; 66 import { ref } from 'vue';
101 import Taro from '@tarojs/taro'; 67 import Taro from '@tarojs/taro';
102 import AppHeader from '../../components/AppHeader.vue'; 68 import AppHeader from '../../components/AppHeader.vue';
103 -import GlassCard from '../../components/GlassCard.vue';
104 -import PrimaryButton from '../../components/PrimaryButton.vue';
105 -import { Ticket, Calendar, Location2, Info, Check, Loading } from '@nutui/icons-vue-taro';
106 -
107 -const redeeming = ref(false);
108 -const redeemed = ref(false);
109 69
110 -// Mock reward data 70 +// Mock reward data based on the image
111 -const reward = { 71 +const reward = ref({
112 id: 1, 72 id: 1,
113 - title: '星巴克咖啡券', 73 + title: '吴良材眼镜店85折券',
114 - description: '任意中杯咖啡一杯', 74 + points: 10,
115 - points: 500, 75 + image: 'https://placehold.co/800x400/e2f3ff/0369a1?text=LFX&font=roboto', // Placeholder image
116 - merchant: '星巴克', 76 + stores: [
117 - image: 'https://upload.wikimedia.org/wikipedia/en/thumb/d/d3/Starbucks_Corporation_Logo_2011.svg/1200px-Starbucks_Corporation_Logo_2011.svg.png', 77 + '吴良材眼镜店 (南京东路店)',
118 - validUntil: '2023年12月31日', 78 + '吴良材眼镜店 (淮海中路店)',
119 - locations: '全国各星巴克门店', 79 + '吴良材眼镜店 (徐家汇店)'
120 - terms: ['每人限兑换1次', '不与其他优惠同享', '使用时请出示兑换码', '最终解释权归商家所有'] 80 + ],
121 -}; 81 + redemption_rules: [
82 + '每人每月限兑换1次',
83 + '兑换后30天内有效',
84 + '兑换成功后不可退回积分'
85 + ],
86 + usage_rules: [
87 + '仅限店内正价商品使用',
88 + '不可与其他优惠同时使用',
89 + '特价商品不可使用',
90 + '最终解释权归商家所有'
91 + ]
92 +});
122 93
94 +/**
95 + * @description Handles the redemption of the coupon.
96 + */
123 const handleRedeem = () => { 97 const handleRedeem = () => {
124 - redeeming.value = true; 98 + // Show a confirmation modal
125 - // Simulate API call 99 + Taro.showModal({
100 + title: '确认兑换',
101 + content: `将消耗 ${reward.value.points} 积分兑换此优惠券,是否确认?`,
102 + success: (res) => {
103 + if (res.confirm) {
104 + // Simulate API call for redemption
105 + Taro.showLoading({ title: '兑换中...' });
106 + setTimeout(() => {
107 + Taro.hideLoading();
108 + Taro.showToast({
109 + title: '兑换成功',
110 + icon: 'success',
111 + duration: 2000
112 + });
113 + // After successful redemption, you might want to navigate the user to their coupons page
114 + // For now, we'll just navigate back.
126 setTimeout(() => { 115 setTimeout(() => {
127 - redeeming.value = false; 116 + Taro.navigateBack();
128 - redeemed.value = true; 117 + }, 2000);
129 }, 1500); 118 }, 1500);
119 + }
120 + }
121 + });
130 }; 122 };
131 -
132 -const goBack = () => {
133 - Taro.navigateTo({ url: '/pages/Rewards/index' });
134 -};
135 -
136 </script> 123 </script>
......
1 <!-- 1 <!--
2 * @Date: 2025-08-27 17:47:26 2 * @Date: 2025-08-27 17:47:26
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2025-08-28 00:10:13 4 + * @LastEditTime: 2025-08-28 09:37:06
5 - * @FilePath: /lls_program/src/pages/Rewards/index.vue
6 - * @Description: 文件描述
7 --->
8 -<!--
9 - * @Date: 2025-08-27 17:47:26
10 - * @LastEditors: hookehuyr hookehuyr@gmail.com
11 - * @LastEditTime: 2025-08-27 23:57:38
12 * @FilePath: /lls_program/src/pages/Rewards/index.vue 5 * @FilePath: /lls_program/src/pages/Rewards/index.vue
13 * @Description: 文件描述 6 * @Description: 文件描述
14 --> 7 -->
...@@ -20,25 +13,32 @@ ...@@ -20,25 +13,32 @@
20 <!-- Content --> 13 <!-- Content -->
21 <view class="relative z-10 flex-1 pb-20"> 14 <view class="relative z-10 flex-1 pb-20">
22 <!-- Points display --> 15 <!-- Points display -->
23 - <view class="pt-4 pb-8 flex flex-col items-center"> 16 + <view class="pt-8 pb-8 flex flex-col items-center">
24 <h2 class="text-4xl font-bold text-white mb-1">2580分</h2> 17 <h2 class="text-4xl font-bold text-white mb-1">2580分</h2>
25 <p class="text-white text-opacity-80">我的积分</p> 18 <p class="text-white text-opacity-80">我的积分</p>
26 </view> 19 </view>
27 <!-- Main content --> 20 <!-- Main content -->
28 <view class="bg-white rounded-t-3xl px-4 pt-5"> 21 <view class="bg-white rounded-t-3xl px-4 pt-5">
29 <!-- Quick exchange options --> 22 <!-- Quick exchange options -->
23 + <!-- Search bar -->
24 + <view class="mb-6">
25 + <view class="relative">
26 + <input type="text" v-model="searchQuery" placeholder="搜索商户名称"
27 + class=" bg-gray-100 rounded-lg py-3 pl-10 pr-4 border border-transparent focus:bg-white focus:border-blue-500 focus:outline-none" />
28 + <view class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
29 + <Search2 size="20" class="text-gray-400" />
30 + </view>
31 + </view>
32 + </view>
33 +
30 <view class="flex gap-3 mb-6"> 34 <view class="flex gap-3 mb-6">
31 - <view 35 + <view v-for="option in quickExchangeOptions" :key="option.points" @click="selectedPoints = option.points"
32 - v-for="option in quickExchangeOptions"
33 - :key="option.points"
34 - @click="selectedPoints = option.points"
35 :class="[ 36 :class="[
36 'flex-1 py-3 rounded-lg border text-center', 37 'flex-1 py-3 rounded-lg border text-center',
37 selectedPoints === option.points 38 selectedPoints === option.points
38 ? 'border-blue-500 bg-blue-50 text-blue-500' 39 ? 'border-blue-500 bg-blue-50 text-blue-500'
39 : 'border-gray-200 text-gray-700' 40 : 'border-gray-200 text-gray-700'
40 - ]" 41 + ]">
41 - >
42 {{ option.label }} 42 {{ option.label }}
43 </view> 43 </view>
44 </view> 44 </view>
...@@ -51,37 +51,48 @@ ...@@ -51,37 +51,48 @@
51 </view> 51 </view>
52 <!-- Rewards list --> 52 <!-- Rewards list -->
53 <view class="space-y-4"> 53 <view class="space-y-4">
54 - <view v-for="reward in sortedRewardItems" :key="reward.id" class="flex items-center border-b border-gray-100 pb-4"> 54 + <view v-for="reward in sortedRewardItems" :key="reward.id"
55 - <view class="w-12 h-12 mr-4 flex-shrink-0"> 55 + class="bg-white rounded-xl p-4 flex items-center shadow-[0_2px_8px_rgba(0,0,0,0.08)]">
56 - <image :src="reward.logo" :alt="reward.title" class="w-full h-full object-contain" /> 56 + <image :src="reward.logo" class="w-16 h-16 rounded-lg mr-4 flex-shrink-0" mode="aspectFill" />
57 - </view> 57 + <view class="flex-1 min-w-0">
58 - <view class="flex-1"> 58 + <view class="font-medium text-base">{{ reward.title }}</view>
59 - <h4 class="font-medium">{{ reward.title }}</h4> 59 + <view class="text-gray-500 text-sm mt-1">{{ reward.merchant }}</view>
60 - <p class="text-gray-500 text-sm">{{ reward.points }}积分</p>
61 </view> 60 </view>
62 - <view class="px-4 py-1 bg-blue-500 text-white rounded-full text-sm" @click="goToRewardDetail(reward)"> 61 + <view class="ml-4 px-4 py-2 bg-blue-500 text-white rounded-lg text-sm flex-shrink-0"
63 - 兑换 62 + @click="goToRewardDetail(reward)">
63 + {{ reward.points }}分兑换
64 </view> 64 </view>
65 </view> 65 </view>
66 </view> 66 </view>
67 </view> 67 </view>
68 </view> 68 </view>
69 - <BottomNav /> 69 + <!-- <BottomNav /> -->
70 </view> 70 </view>
71 </template> 71 </template>
72 72
73 <script setup> 73 <script setup>
74 import { ref, computed } from 'vue'; 74 import { ref, computed } from 'vue';
75 import Taro from '@tarojs/taro'; 75 import Taro from '@tarojs/taro';
76 -import { ScreenLittle } from '@nutui/icons-vue-taro'; 76 +import { ScreenLittle, Search2 } from '@nutui/icons-vue-taro';
77 import AppHeader from '../../components/AppHeader.vue'; 77 import AppHeader from '../../components/AppHeader.vue';
78 import BottomNav from '../../components/BottomNav.vue'; 78 import BottomNav from '../../components/BottomNav.vue';
79 79
80 +const searchQuery = ref('');
80 const selectedPoints = ref(null); 81 const selectedPoints = ref(null);
81 const sortOrder = ref('desc'); // 'asc' or 'desc' 82 const sortOrder = ref('desc'); // 'asc' or 'desc'
82 83
83 const sortedRewardItems = computed(() => { 84 const sortedRewardItems = computed(() => {
84 - return [...rewardItems.value].sort((a, b) => { 85 + let items = [...rewardItems.value];
86 +
87 + // Filter by search query
88 + if (searchQuery.value) {
89 + items = items.filter(item =>
90 + item.merchant.toLowerCase().includes(searchQuery.value.toLowerCase())
91 + );
92 + }
93 +
94 + // Sort items
95 + return items.sort((a, b) => {
85 if (sortOrder.value === 'asc') { 96 if (sortOrder.value === 'asc') {
86 return a.points - b.points; 97 return a.points - b.points;
87 } else { 98 } else {
...@@ -97,33 +108,38 @@ const toggleSortOrder = () => { ...@@ -97,33 +108,38 @@ const toggleSortOrder = () => {
97 const rewardItems = ref([ 108 const rewardItems = ref([
98 { 109 {
99 id: 1, 110 id: 1,
100 - title: '星巴克中杯咖啡兑换券', 111 + logo: 'https://placehold.co/400x400/e2f3ff/0369a1?text=LFX&font=roboto',
101 - points: 1000, 112 + title: '杏花楼集团85折券',
102 - logo: 'https://upload.wikimedia.org/wikipedia/en/thumb/d/d3/Starbucks_Corporation_Logo_2011.svg/1200px-Starbucks_Corporation_Logo_2011.svg.png' 113 + merchant: '杏花楼集团',
114 + points: 10
103 }, 115 },
104 { 116 {
105 id: 2, 117 id: 2,
106 - title: '老凤祥20元抵用券', 118 + logo: 'https://placehold.co/400x400/e2f3ff/0369a1?text=LFX&font=roboto',
107 - points: 600, 119 + title: '吴良材眼镜店85折券',
108 - logo: 'https://placehold.co/400x400/e2f3ff/0369a1?text=LFX&font=roboto' 120 + merchant: '吴良材眼镜店',
121 + points: 10
109 }, 122 },
110 { 123 {
111 id: 3, 124 id: 3,
112 - title: '杏花楼集团8折券', 125 + logo: 'https://placehold.co/400x400/e2f3ff/0369a1?text=LFX&font=roboto',
113 - points: 500, 126 + title: '老凤祥银楼20元抵用券',
114 - logo: 'https://placehold.co/400x400/e2f3ff/0369a1?text=XHL&font=roboto' 127 + merchant: '老凤祥银楼',
128 + points: 1000
115 }, 129 },
116 { 130 {
117 id: 4, 131 id: 4,
118 - title: '肯德基汉堡套餐券', 132 + logo: 'https://placehold.co/400x400/e2f3ff/0369a1?text=LFX&font=roboto',
119 - points: 1000, 133 + title: '沈大成双酿团2元抵用券',
120 - logo: 'https://upload.wikimedia.org/wikipedia/en/thumb/b/bf/KFC_logo.svg/1200px-KFC_logo.svg.png' 134 + merchant: '沈大成双酿团',
135 + points: 100
121 }, 136 },
122 { 137 {
123 id: 5, 138 id: 5,
124 - title: '沈大成双黄团3元抵用券', 139 + logo: 'https://placehold.co/400x400/e2f3ff/0369a1?text=LFX&font=roboto',
125 - points: 300, 140 + title: '这是一个非常非常非常非常非常长的标题用于测试换行效果',
126 - logo: 'https://placehold.co/400x400/e2f3ff/0369a1?text=SDC&font=roboto' 141 + merchant: '一个名字很长的商家',
142 + points: 500
127 } 143 }
128 ]); 144 ]);
129 145
......
1 export default { 1 export default {
2 - navigationBarTitleText: '首页' 2 + navigationBarTitleText: '用户协议'
3 } 3 }
......
1 +<!--
2 + * @Date: 2025-08-27 17:50:27
3 + * @LastEditors: hookehuyr hookehuyr@gmail.com
4 + * @LastEditTime: 2025-08-28 00:31:28
5 + * @FilePath: /lls_program/src/pages/UserAgreement/index.vue
6 + * @Description: 文件描述
7 +-->
1 <template> 8 <template>
2 <view class="min-h-screen flex flex-col bg-white"> 9 <view class="min-h-screen flex flex-col bg-white">
3 - <AppHeader title="用户协议" /> 10 + <!-- <AppHeader title="用户协议" /> -->
4 <view class="flex-1 px-4 py-6 pb-20"> 11 <view class="flex-1 px-4 py-6 pb-20">
5 <view class="prose prose-sm max-w-none"> 12 <view class="prose prose-sm max-w-none">
6 <h2 class="text-xl font-bold mb-4">老来赛用户协议</h2> 13 <h2 class="text-xl font-bold mb-4">老来赛用户协议</h2>
...@@ -87,7 +94,7 @@ ...@@ -87,7 +94,7 @@
87 <p class="text-gray-700 mt-8">本协议最终解释权归老来赛所有。</p> 94 <p class="text-gray-700 mt-8">本协议最终解释权归老来赛所有。</p>
88 </view> 95 </view>
89 </view> 96 </view>
90 - <BottomNav /> 97 + <!-- <BottomNav /> -->
91 </view> 98 </view>
92 </template> 99 </template>
93 100
......