hookehuyr

chore: 将品牌名称从“美乐爱觉”更新为“生命力教育联盟”

更新所有页面、组件和文档中的品牌名称,包括用户协议、页面标题、分享标题、海报文案等,以反映品牌名称变更
...@@ -12,35 +12,49 @@ ...@@ -12,35 +12,49 @@
12 position="bottom" 12 position="bottom"
13 :style="{ height: '100%' }" 13 :style="{ height: '100%' }"
14 > 14 >
15 - <div class="flex flex-col h-full relative"> 15 + <div class="relative flex h-full flex-col">
16 - <div class="sticky top-0 flex justify-between items-center p-4 border-b border-gray-100 bg-white z-10"> 16 + <div
17 - <h3 class="font-medium text-lg">{{ title }}</h3> 17 + class="sticky top-0 z-10 flex items-center justify-between border-b border-gray-100 bg-white p-4"
18 + >
19 + <h3 class="text-lg font-medium">{{ title }}</h3>
18 <van-icon name="cross" @click="$emit('update:show', false)" class="text-gray-500" /> 20 <van-icon name="cross" @click="$emit('update:show', false)" class="text-gray-500" />
19 </div> 21 </div>
20 22
21 <div class="flex-1 overflow-y-auto p-4 pt-0"> 23 <div class="flex-1 overflow-y-auto p-4 pt-0">
22 <div v-if="type === 'terms'" class="space-y-4 text-gray-600"> 24 <div v-if="type === 'terms'" class="space-y-4 text-gray-600">
23 - <p>欢迎使用美乐爱觉教育!在使用我们的服务之前,请仔细阅读以下用户协议。</p> 25 + <p>欢迎使用生命力教育联盟教育!在使用我们的服务之前,请仔细阅读以下用户协议。</p>
24 26
25 <h5 class="font-medium text-gray-800">1. 服务内容</h5> 27 <h5 class="font-medium text-gray-800">1. 服务内容</h5>
26 - <p>美乐爱觉教育为用户提供在线教育、活动报名等服务。我们保留随时修改或中断服务的权利,而无需事先通知用户。</p> 28 + <p>
29 + 生命力教育联盟教育为用户提供在线教育、活动报名等服务。我们保留随时修改或中断服务的权利,而无需事先通知用户。
30 + </p>
27 31
28 <h5 class="font-medium text-gray-800">2. 用户责任</h5> 32 <h5 class="font-medium text-gray-800">2. 用户责任</h5>
29 - <p>用户在使用本服务时必须遵守所有适用的法律法规。用户承诺提供真实、准确、完整的个人信息。</p> 33 + <p>
34 + 用户在使用本服务时必须遵守所有适用的法律法规。用户承诺提供真实、准确、完整的个人信息。
35 + </p>
30 36
31 <h5 class="font-medium text-gray-800">3. 知识产权</h5> 37 <h5 class="font-medium text-gray-800">3. 知识产权</h5>
32 - <p>本平台的所有内容,包括但不限于文字、图片、音频、视频等,均受著作权法和其他知识产权法律法规的保护。</p> 38 + <p>
39 + 本平台的所有内容,包括但不限于文字、图片、音频、视频等,均受著作权法和其他知识产权法律法规的保护。
40 + </p>
33 41
34 <h5 class="font-medium text-gray-800">4. 免责声明</h5> 42 <h5 class="font-medium text-gray-800">4. 免责声明</h5>
35 <p>对于因不可抗力或非本平台原因造成的服务中断或其他缺陷,本平台不承担任何责任。</p> 43 <p>对于因不可抗力或非本平台原因造成的服务中断或其他缺陷,本平台不承担任何责任。</p>
36 <h5 class="font-medium text-gray-800">1. 服务内容</h5> 44 <h5 class="font-medium text-gray-800">1. 服务内容</h5>
37 - <p>美乐爱觉教育为用户提供在线教育、活动报名等服务。我们保留随时修改或中断服务的权利,而无需事先通知用户。</p> 45 + <p>
46 + 生命力教育联盟教育为用户提供在线教育、活动报名等服务。我们保留随时修改或中断服务的权利,而无需事先通知用户。
47 + </p>
38 48
39 <h5 class="font-medium text-gray-800">2. 用户责任</h5> 49 <h5 class="font-medium text-gray-800">2. 用户责任</h5>
40 - <p>用户在使用本服务时必须遵守所有适用的法律法规。用户承诺提供真实、准确、完整的个人信息。</p> 50 + <p>
51 + 用户在使用本服务时必须遵守所有适用的法律法规。用户承诺提供真实、准确、完整的个人信息。
52 + </p>
41 53
42 <h5 class="font-medium text-gray-800">3. 知识产权</h5> 54 <h5 class="font-medium text-gray-800">3. 知识产权</h5>
43 - <p>本平台的所有内容,包括但不限于文字、图片、音频、视频等,均受著作权法和其他知识产权法律法规的保护。</p> 55 + <p>
56 + 本平台的所有内容,包括但不限于文字、图片、音频、视频等,均受著作权法和其他知识产权法律法规的保护。
57 + </p>
44 58
45 <h5 class="font-medium text-gray-800">4. 免责声明</h5> 59 <h5 class="font-medium text-gray-800">4. 免责声明</h5>
46 <p>对于因不可抗力或非本平台原因造成的服务中断或其他缺陷,本平台不承担任何责任。</p> 60 <p>对于因不可抗力或非本平台原因造成的服务中断或其他缺陷,本平台不承担任何责任。</p>
...@@ -50,10 +64,14 @@ ...@@ -50,10 +64,14 @@
50 <p>我们重视您的隐私保护。本隐私政策说明我们如何收集、使用和保护您的个人信息。</p> 64 <p>我们重视您的隐私保护。本隐私政策说明我们如何收集、使用和保护您的个人信息。</p>
51 65
52 <h5 class="font-medium text-gray-800">1. 信息收集</h5> 66 <h5 class="font-medium text-gray-800">1. 信息收集</h5>
53 - <p>我们收集的信息包括但不限于:姓名、联系方式、位置信息等。这些信息用于提供更好的服务体验。</p> 67 + <p>
68 + 我们收集的信息包括但不限于:姓名、联系方式、位置信息等。这些信息用于提供更好的服务体验。
69 + </p>
54 70
55 <h5 class="font-medium text-gray-800">2. 信息使用</h5> 71 <h5 class="font-medium text-gray-800">2. 信息使用</h5>
56 - <p>我们承诺对您的个人信息进行严格保密,不会将其出售、出租或以其他方式泄露给任何第三方。</p> 72 + <p>
73 + 我们承诺对您的个人信息进行严格保密,不会将其出售、出租或以其他方式泄露给任何第三方。
74 + </p>
57 75
58 <h5 class="font-medium text-gray-800">3. 信息安全</h5> 76 <h5 class="font-medium text-gray-800">3. 信息安全</h5>
59 <p>我们采用行业标准的安全措施保护您的个人信息,防止未经授权的访问、使用或泄露。</p> 77 <p>我们采用行业标准的安全措施保护您的个人信息,防止未经授权的访问、使用或泄露。</p>
...@@ -72,19 +90,19 @@ defineProps({ ...@@ -72,19 +90,19 @@ defineProps({
72 show: { 90 show: {
73 type: Boolean, 91 type: Boolean,
74 required: true, 92 required: true,
75 - default: false 93 + default: false,
76 }, 94 },
77 /** 协议类型: 'terms' | 'privacy' */ 95 /** 协议类型: 'terms' | 'privacy' */
78 type: { 96 type: {
79 type: String, 97 type: String,
80 required: true, 98 required: true,
81 - validator: (value) => ['terms', 'privacy'].includes(value) 99 + validator: value => ['terms', 'privacy'].includes(value),
82 }, 100 },
83 /** 弹窗标题 */ 101 /** 弹窗标题 */
84 title: { 102 title: {
85 type: String, 103 type: String,
86 - required: true 104 + required: true,
87 - } 105 + },
88 }) 106 })
89 107
90 defineEmits(['update:show']) 108 defineEmits(['update:show'])
......
...@@ -9,69 +9,81 @@ ...@@ -9,69 +9,81 @@
9 * @Description: 用户协议组件 9 * @Description: 用户协议组件
10 --> 10 -->
11 <template> 11 <template>
12 - <van-popup 12 + <van-popup v-model:show="show" round position="bottom" :style="{ height: '90%' }" teleport="body">
13 - v-model:show="show"
14 - round
15 - position="bottom"
16 - :style="{ height: '90%' }"
17 - teleport="body"
18 - >
19 <div class="p-4"> 13 <div class="p-4">
20 - <div class="text-xl font-bold text-center mb-4">美乐爱觉宇宙用户协议</div> 14 + <div class="mb-4 text-center text-xl font-bold">生命力教育联盟宇宙用户协议</div>
21 - <div class="agreement-content overflow-y-auto h-[calc(100vh*0.8-120px)] px-2"> 15 + <div class="agreement-content h-[calc(100vh*0.8-120px)] overflow-y-auto px-2">
22 - <h2 class="text-lg font-semibold mb-3">1. 协议的范围</h2> 16 + <h2 class="mb-3 text-lg font-semibold">1. 协议的范围</h2>
23 - <p class="mb-4 text-gray-700">欢迎您使用美乐爱觉宇宙平台服务!为使用美乐爱觉宇宙平台服务,您应当阅读并遵守本《用户协议》。请您务必审慎阅读、充分理解各条款内容。</p> 17 + <p class="mb-4 text-gray-700">
18 + 欢迎您使用生命力教育联盟宇宙平台服务!为使用生命力教育联盟宇宙平台服务,您应当阅读并遵守本《用户协议》。请您务必审慎阅读、充分理解各条款内容。
19 + </p>
24 20
25 - <h2 class="text-lg font-semibold mb-3">2. 账号注册</h2> 21 + <h2 class="mb-3 text-lg font-semibold">2. 账号注册</h2>
26 - <p class="mb-4 text-gray-700">您在使用本服务前需要注册一个美乐爱觉宇宙账号。美乐爱觉宇宙账号应当使用手机号码绑定注册,请您使用尚未与美乐爱觉宇宙账号绑定的手机号码,以及未被平台根据本协议封禁的手机号码注册。</p> 22 + <p class="mb-4 text-gray-700">
23 + 您在使用本服务前需要注册一个生命力教育联盟宇宙账号。生命力教育联盟宇宙账号应当使用手机号码绑定注册,请您使用尚未与生命力教育联盟宇宙账号绑定的手机号码,以及未被平台根据本协议封禁的手机号码注册。
24 + </p>
27 25
28 - <h2 class="text-lg font-semibold mb-3">3. 用户个人信息保护</h2> 26 + <h2 class="mb-3 text-lg font-semibold">3. 用户个人信息保护</h2>
29 - <p class="mb-4 text-gray-700">我们非常重视用户个人信息的保护,保护用户个人信息是我们的基本原则之一。我们将会采取合理的措施保护用户的个人信息。除法律法规规定的情形外,未经用户许可我们不会向第三方公开、透露用户个人信息。</p> 27 + <p class="mb-4 text-gray-700">
28 + 我们非常重视用户个人信息的保护,保护用户个人信息是我们的基本原则之一。我们将会采取合理的措施保护用户的个人信息。除法律法规规定的情形外,未经用户许可我们不会向第三方公开、透露用户个人信息。
29 + </p>
30 30
31 - <h2 class="text-lg font-semibold mb-3">4. 内容规范</h2> 31 + <h2 class="mb-3 text-lg font-semibold">4. 内容规范</h2>
32 - <p class="mb-4 text-gray-700">您在使用本服务时需要遵守法律法规、社会主义制度、国家利益、公民合法权益、公共秩序、社会道德风尚和信息真实性等七条底线。</p> 32 + <p class="mb-4 text-gray-700">
33 + 您在使用本服务时需要遵守法律法规、社会主义制度、国家利益、公民合法权益、公共秩序、社会道德风尚和信息真实性等七条底线。
34 + </p>
33 35
34 - <h2 class="text-lg font-semibold mb-3">5. 知识产权</h2> 36 + <h2 class="mb-3 text-lg font-semibold">5. 知识产权</h2>
35 - <p class="mb-4 text-gray-700">美乐爱觉宇宙平台所包含的全部智力成果,包括但不限于平台内容、平台设计、源代码等,均属于平台所有。未经平台许可,任何人不得擅自使用。</p> 37 + <p class="mb-4 text-gray-700">
38 + 生命力教育联盟宇宙平台所包含的全部智力成果,包括但不限于平台内容、平台设计、源代码等,均属于平台所有。未经平台许可,任何人不得擅自使用。
39 + </p>
36 40
37 - <h2 class="text-lg font-semibold mb-3">6. 服务的变更、中断和终止</h2> 41 + <h2 class="mb-3 text-lg font-semibold">6. 服务的变更、中断和终止</h2>
38 - <p class="mb-4 text-gray-700">我们可能会对服务内容进行变更,也可能会中断、中止或终止服务。对于付费服务,我们会在变更前通知您,并向您提供退款等必要的补偿。</p> 42 + <p class="mb-4 text-gray-700">
43 + 我们可能会对服务内容进行变更,也可能会中断、中止或终止服务。对于付费服务,我们会在变更前通知您,并向您提供退款等必要的补偿。
44 + </p>
39 45
40 - <h2 class="text-lg font-semibold mb-3">7. 违约处理</h2> 46 + <h2 class="mb-3 text-lg font-semibold">7. 违约处理</h2>
41 - <p class="mb-4 text-gray-700">如果您违反本协议约定,我们有权视情况采取预先警示、限制或禁止使用全部或部分服务功能、封禁账号等措施。</p> 47 + <p class="mb-4 text-gray-700">
48 + 如果您违反本协议约定,我们有权视情况采取预先警示、限制或禁止使用全部或部分服务功能、封禁账号等措施。
49 + </p>
42 50
43 - <h2 class="text-lg font-semibold mb-3">8. 其他条款</h2> 51 + <h2 class="mb-3 text-lg font-semibold">8. 其他条款</h2>
44 - <p class="mb-4 text-gray-700">本协议所有条款的标题仅为阅读方便,本身并无实际涵义,不能作为本协议涵义解释的依据。如果本协议中任何一条被视为废止、无效或不可执行,应视为可分的且并不影响任何其余条款的有效性和可执行性。</p> 52 + <p class="mb-4 text-gray-700">
53 + 本协议所有条款的标题仅为阅读方便,本身并无实际涵义,不能作为本协议涵义解释的依据。如果本协议中任何一条被视为废止、无效或不可执行,应视为可分的且并不影响任何其余条款的有效性和可执行性。
54 + </p>
45 </div> 55 </div>
46 - <div class="flex justify-center mt-4"> 56 + <div class="mt-4 flex justify-center">
47 - <van-button round type="primary" color="#4CAF50" block @click="handleClose">我已阅读并同意</van-button> 57 + <van-button round type="primary" color="#4CAF50" block @click="handleClose"
58 + >我已阅读并同意</van-button
59 + >
48 </div> 60 </div>
49 </div> 61 </div>
50 </van-popup> 62 </van-popup>
51 </template> 63 </template>
52 64
53 <script setup> 65 <script setup>
54 -import { ref, defineExpose } from 'vue'; 66 +import { ref, defineExpose } from 'vue'
55 67
56 -const show = ref(false); 68 +const show = ref(false)
57 69
58 /** 70 /**
59 * @description 关闭协议弹窗 71 * @description 关闭协议弹窗
60 */ 72 */
61 const handleClose = () => { 73 const handleClose = () => {
62 - show.value = false; 74 + show.value = false
63 -}; 75 +}
64 76
65 /** 77 /**
66 * @description 打开协议弹窗 78 * @description 打开协议弹窗
67 */ 79 */
68 const openAgreement = () => { 80 const openAgreement = () => {
69 - show.value = true; 81 + show.value = true
70 -}; 82 +}
71 83
72 defineExpose({ 84 defineExpose({
73 - openAgreement 85 + openAgreement,
74 -}); 86 +})
75 </script> 87 </script>
76 88
77 <style lang="less" scoped> 89 <style lang="less" scoped>
......
1 <template> 1 <template>
2 - <div class="recall-poster-container w-full max-w-[340px] relative select-none shrink-0 my-auto mx-auto"> 2 + <div
3 + class="recall-poster-container relative mx-auto my-auto w-full max-w-[340px] shrink-0 select-none"
4 + >
3 <!-- 最终生成的海报图片展示区域 --> 5 <!-- 最终生成的海报图片展示区域 -->
4 - <div v-if="posterImgSrc" class="relative w-full fade-in"> 6 + <div v-if="posterImgSrc" class="fade-in relative w-full">
5 - <img :src="posterImgSrc" class="w-full h-auto rounded-2xl shadow-2xl block" alt="分享海报" /> 7 + <img :src="posterImgSrc" class="block h-auto w-full rounded-2xl shadow-2xl" alt="分享海报" />
6 - <div class="text-white/80 text-center text-xs mt-4">长按图片保存</div> 8 + <div class="mt-4 text-center text-xs text-white/80">长按图片保存</div>
7 </div> 9 </div>
8 10
9 <!-- 生成中/加载中占位 --> 11 <!-- 生成中/加载中占位 -->
10 - <div v-else 12 + <div
11 - class="w-full h-[62vh] min-h-[400px] bg-white/10 backdrop-blur-sm rounded-2xl flex flex-col items-center justify-center text-white/80"> 13 + v-else
14 + class="flex h-[62vh] min-h-[400px] w-full flex-col items-center justify-center rounded-2xl bg-white/10 text-white/80 backdrop-blur-sm"
15 + >
12 <van-loading type="spinner" color="#ffffff" size="32px" /> 16 <van-loading type="spinner" color="#ffffff" size="32px" />
13 <div class="mt-4 text-sm font-medium">海报生成中...</div> 17 <div class="mt-4 text-sm font-medium">海报生成中...</div>
14 </div> 18 </div>
...@@ -27,31 +31,31 @@ const props = defineProps({ ...@@ -27,31 +31,31 @@ const props = defineProps({
27 /** 海报背景图片 URL */ 31 /** 海报背景图片 URL */
28 bgUrl: { 32 bgUrl: {
29 type: String, 33 type: String,
30 - required: true 34 + required: true,
31 }, 35 },
32 /** 海报标题 */ 36 /** 海报标题 */
33 title: { 37 title: {
34 type: String, 38 type: String,
35 - default: '' 39 + default: '',
36 }, 40 },
37 /** Logo 图片 URL */ 41 /** Logo 图片 URL */
38 logoUrl: { 42 logoUrl: {
39 type: String, 43 type: String,
40 - default: 'https://cdn.ipadbiz.cn/mlaj/recall/poster/kai@2x.png' 44 + default: 'https://cdn.ipadbiz.cn/mlaj/recall/poster/kai@2x.png',
41 }, 45 },
42 /** 二维码图片 URL */ 46 /** 二维码图片 URL */
43 qrUrl: { 47 qrUrl: {
44 type: String, 48 type: String,
45 - default: 'https://cdn.ipadbiz.cn/mlaj/recall/poster/%E4%BA%8C%E7%BB%B4%E7%A0%81@2x.png' 49 + default: 'https://cdn.ipadbiz.cn/mlaj/recall/poster/%E4%BA%8C%E7%BB%B4%E7%A0%81@2x.png',
46 - } 50 + },
47 }) 51 })
48 52
49 const canvasRef = ref(null) 53 const canvasRef = ref(null)
50 const posterImgSrc = ref('') 54 const posterImgSrc = ref('')
51 55
52 // 工具函数:加载图片 56 // 工具函数:加载图片
53 -const loadImage = (src) => { 57 +const loadImage = src =>
54 - return new Promise((resolve, reject) => { 58 + new Promise((resolve, reject) => {
55 if (!src) { 59 if (!src) {
56 reject(new Error('Image source is empty')) 60 reject(new Error('Image source is empty'))
57 return 61 return
...@@ -62,7 +66,7 @@ const loadImage = (src) => { ...@@ -62,7 +66,7 @@ const loadImage = (src) => {
62 img.crossOrigin = 'anonymous' 66 img.crossOrigin = 'anonymous'
63 } 67 }
64 img.onload = () => resolve(img) 68 img.onload = () => resolve(img)
65 - img.onerror = (e) => { 69 + img.onerror = e => {
66 console.error('Failed to load image:', src) 70 console.error('Failed to load image:', src)
67 // 图片加载失败不应该阻断流程,返回 null 或者透明图占位 71 // 图片加载失败不应该阻断流程,返回 null 或者透明图占位
68 // 这里resolve null,绘制时跳过 72 // 这里resolve null,绘制时跳过
...@@ -70,7 +74,6 @@ const loadImage = (src) => { ...@@ -70,7 +74,6 @@ const loadImage = (src) => {
70 } 74 }
71 img.src = src 75 img.src = src
72 }) 76 })
73 -}
74 77
75 // 工具函数:绘制圆角矩形 78 // 工具函数:绘制圆角矩形
76 const drawRoundedRect = (ctx, x, y, width, height, radius) => { 79 const drawRoundedRect = (ctx, x, y, width, height, radius) => {
...@@ -170,7 +173,10 @@ const generatePoster = async () => { ...@@ -170,7 +173,10 @@ const generatePoster = async () => {
170 let qrUrlToLoad = props.qrUrl 173 let qrUrlToLoad = props.qrUrl
171 let qrBlobUrl = null 174 let qrBlobUrl = null
172 // 兼容完整 URL 和相对路径,只要包含特定特征或是相对路径 175 // 兼容完整 URL 和相对路径,只要包含特定特征或是相对路径
173 - if (qrUrlToLoad && (qrUrlToLoad.startsWith('/') || qrUrlToLoad.includes('m=srv') || qrUrlToLoad.includes('http'))) { 176 + if (
177 + qrUrlToLoad &&
178 + (qrUrlToLoad.startsWith('/') || qrUrlToLoad.includes('m=srv') || qrUrlToLoad.includes('http'))
179 + ) {
174 try { 180 try {
175 // 使用 fetch 替代 axios,避免拦截器自动添加 header 导致 CORS 预检失败 181 // 使用 fetch 替代 axios,避免拦截器自动添加 header 导致 CORS 预检失败
176 const res = await fetch(qrUrlToLoad) 182 const res = await fetch(qrUrlToLoad)
...@@ -188,7 +194,7 @@ const generatePoster = async () => { ...@@ -188,7 +194,7 @@ const generatePoster = async () => {
188 const [bgImg, logoImg, qrImg] = await Promise.all([ 194 const [bgImg, logoImg, qrImg] = await Promise.all([
189 loadImage(props.bgUrl), 195 loadImage(props.bgUrl),
190 loadImage(props.logoUrl), 196 loadImage(props.logoUrl),
191 - loadImage(qrUrlToLoad) 197 + loadImage(qrUrlToLoad),
192 ]) 198 ])
193 199
194 // 清理 Blob URL 200 // 清理 Blob URL
...@@ -250,13 +256,13 @@ const generatePoster = async () => { ...@@ -250,13 +256,13 @@ const generatePoster = async () => {
250 ctx.shadowOffsetY = 1 * scale 256 ctx.shadowOffsetY = 1 * scale
251 257
252 // Column 1: "每一段成长故事" (左边那列,离右边远一点) 258 // Column 1: "每一段成长故事" (左边那列,离右边远一点)
253 - // Column 2: "见证我在美乐爱觉宇宙的" (右边那列) 259 + // Column 2: "见证我在生命力教育联盟宇宙的" (右边那列)
254 260
255 - const colRightX = width - textRightMargin - (fontSize / 2) 261 + const colRightX = width - textRightMargin - fontSize / 2
256 const colLeftX = colRightX - fontSize - 12 * scale // gap-3 = 12px 262 const colLeftX = colRightX - fontSize - 12 * scale // gap-3 = 12px
257 263
258 - const textRight = "见证我在美乐爱觉宇宙的" 264 + const textRight = '见证我在生命力教育联盟宇宙的'
259 - const textLeft = "每一段成长故事" 265 + const textLeft = '每一段成长故事'
260 266
261 // 计算文本对齐 267 // 计算文本对齐
262 // 目标:整个文本块的底部与 bottom-6 对齐 268 // 目标:整个文本块的底部与 bottom-6 对齐
...@@ -294,7 +300,6 @@ const generatePoster = async () => { ...@@ -294,7 +300,6 @@ const generatePoster = async () => {
294 300
295 ctx.shadowColor = 'transparent' 301 ctx.shadowColor = 'transparent'
296 302
297 -
298 // 6. 绘制 Info Area 内容 303 // 6. 绘制 Info Area 内容
299 // 坐标参考 304 // 坐标参考
300 const infoY = imgAreaHeight 305 const infoY = imgAreaHeight
...@@ -313,7 +318,7 @@ const generatePoster = async () => { ...@@ -313,7 +318,7 @@ const generatePoster = async () => {
313 const titleX = padding 318 const titleX = padding
314 const titleY = infoY + padding 319 const titleY = infoY + padding
315 const qrSectionW = 85 * scale // approx 320 const qrSectionW = 85 * scale // approx
316 - const titleMaxW = width - padding - qrSectionW - (10 * scale) // extra gap 321 + const titleMaxW = width - padding - qrSectionW - 10 * scale // extra gap
317 322
318 ctx.fillStyle = '#0052D9' 323 ctx.fillStyle = '#0052D9'
319 ctx.font = `bold ${15 * scale}px sans-serif` 324 ctx.font = `bold ${15 * scale}px sans-serif`
...@@ -331,7 +336,7 @@ const generatePoster = async () => { ...@@ -331,7 +336,7 @@ const generatePoster = async () => {
331 // Section starts at width - padding - qrSectionW? 336 // Section starts at width - padding - qrSectionW?
332 // Actually DOM is flex justify-between. 337 // Actually DOM is flex justify-between.
333 // QR is at the very right (minus padding). 338 // QR is at the very right (minus padding).
334 - const qrX = width - padding - qrSize + (4 * scale) // slight adjustment 339 + const qrX = width - padding - qrSize + 4 * scale // slight adjustment
335 const qrY = infoY + padding 340 const qrY = infoY + padding
336 341
337 ctx.drawImage(qrImg, qrX, qrY, qrSize, qrSize) 342 ctx.drawImage(qrImg, qrX, qrY, qrSize, qrSize)
...@@ -345,24 +350,26 @@ const generatePoster = async () => { ...@@ -345,24 +350,26 @@ const generatePoster = async () => {
345 ctx.textAlign = 'center' 350 ctx.textAlign = 'center'
346 351
347 const textCenterX = qrX + qrSize / 2 352 const textCenterX = qrX + qrSize / 2
348 - const textStartY = qrY + qrSize + (8 * scale) // mb-2 is for img 353 + const textStartY = qrY + qrSize + 8 * scale // mb-2 is for img
349 354
350 - ctx.fillText("跟我一起加入", textCenterX, textStartY) 355 + ctx.fillText('跟我一起加入', textCenterX, textStartY)
351 - ctx.fillText("美乐爱觉宇宙吧", textCenterX, textStartY + smallTextSize * 1.4) 356 + ctx.fillText('生命力教育联盟宇宙吧', textCenterX, textStartY + smallTextSize * 1.4)
352 } 357 }
353 358
354 // 7. 导出图片 359 // 7. 导出图片
355 posterImgSrc.value = canvas.toDataURL('image/png') 360 posterImgSrc.value = canvas.toDataURL('image/png')
356 -
357 } catch (error) { 361 } catch (error) {
358 console.error('Canvas poster generation failed:', error) 362 console.error('Canvas poster generation failed:', error)
359 showToast('生成失败,请重试') 363 showToast('生成失败,请重试')
360 } 364 }
361 } 365 }
362 366
363 -watch(() => [props.bgUrl, props.qrUrl], () => { 367 +watch(
368 + () => [props.bgUrl, props.qrUrl],
369 + () => {
364 generatePoster() 370 generatePoster()
365 -}) 371 + }
372 +)
366 373
367 onMounted(() => { 374 onMounted(() => {
368 // 稍微延时确保字体等资源就绪(虽然canvas不强依赖DOM渲染,但字体加载是全局的) 375 // 稍微延时确保字体等资源就绪(虽然canvas不强依赖DOM渲染,但字体加载是全局的)
...@@ -370,7 +377,7 @@ onMounted(() => { ...@@ -370,7 +377,7 @@ onMounted(() => {
370 }) 377 })
371 378
372 defineExpose({ 379 defineExpose({
373 - generatePoster 380 + generatePoster,
374 }) 381 })
375 </script> 382 </script>
376 383
......
...@@ -8,12 +8,12 @@ ...@@ -8,12 +8,12 @@
8 <template> 8 <template>
9 <div class="welcome-content"> 9 <div class="welcome-content">
10 <!-- 标题区域 --> 10 <!-- 标题区域 -->
11 - <div class="mt-20 flex flex-col items-center z-10 w-full px-8"> 11 + <div class="z-10 mt-20 flex w-full flex-col items-center px-8">
12 - <img :src="titleImg" class="w-full max-w-[300px] mb-4 object-contain" alt="美乐爱觉" /> 12 + <img :src="titleImg" class="mb-4 w-full max-w-[300px] object-contain" alt="生命力教育联盟" />
13 </div> 13 </div>
14 14
15 <!-- 功能入口区域 - 水平布局,自动推到底部 --> 15 <!-- 功能入口区域 - 水平布局,自动推到底部 -->
16 - <div class="mt-auto entry-orbit"> 16 + <div class="entry-orbit mt-auto">
17 <div class="orbit-entries"> 17 <div class="orbit-entries">
18 <WelcomeEntryItem 18 <WelcomeEntryItem
19 v-for="entry in entries" 19 v-for="entry in entries"
...@@ -39,7 +39,7 @@ const entries = ref(welcomeEntries) ...@@ -39,7 +39,7 @@ const entries = ref(welcomeEntries)
39 // 导入标题图片 39 // 导入标题图片
40 const titleImg = 'https://cdn.ipadbiz.cn/mlaj/recall/img/title007@2x.png' 40 const titleImg = 'https://cdn.ipadbiz.cn/mlaj/recall/img/title007@2x.png'
41 41
42 -const handleEntryClick = (entry) => { 42 +const handleEntryClick = entry => {
43 if (entry.isExternal) { 43 if (entry.isExternal) {
44 // 外部链接:获取用户ID并拼接 44 // 外部链接:获取用户ID并拼接
45 const currentUser = JSON.parse(localStorage.getItem('currentUser') || '{}') 45 const currentUser = JSON.parse(localStorage.getItem('currentUser') || '{}')
...@@ -103,7 +103,8 @@ const handleEntryClick = (entry) => { ...@@ -103,7 +103,8 @@ const handleEntryClick = (entry) => {
103 103
104 // 动画定义 104 // 动画定义
105 @keyframes float { 105 @keyframes float {
106 - 0%, 100% { 106 + 0%,
107 + 100% {
107 transform: translateY(0); 108 transform: translateY(0);
108 } 109 }
109 50% { 110 50% {
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
5 * @FilePath: /mlaj/src/composables/useShare.js 5 * @FilePath: /mlaj/src/composables/useShare.js
6 * @Description: 微信分享相关逻辑 6 * @Description: 微信分享相关逻辑
7 */ 7 */
8 -import wx from 'weixin-js-sdk'; 8 +import wx from 'weixin-js-sdk'
9 9
10 /** 10 /**
11 * @function normalize_image_url 11 * @function normalize_image_url
...@@ -14,15 +14,15 @@ import wx from 'weixin-js-sdk'; ...@@ -14,15 +14,15 @@ import wx from 'weixin-js-sdk';
14 * @returns {string} 处理后的图片地址 14 * @returns {string} 处理后的图片地址
15 */ 15 */
16 function normalize_image_url(src) { 16 function normalize_image_url(src) {
17 - if (!src) return ''; 17 + if (!src) return ''
18 if (src.includes('cdn.ipadbiz.cn')) { 18 if (src.includes('cdn.ipadbiz.cn')) {
19 - const compress = 'imageMogr2/thumbnail/200x/strip/quality/70'; 19 + const compress = 'imageMogr2/thumbnail/200x/strip/quality/70'
20 if (src.includes('?')) { 20 if (src.includes('?')) {
21 - return src.includes(compress) ? src : `${src}&${compress}`; 21 + return src.includes(compress) ? src : `${src}&${compress}`
22 } 22 }
23 - return `${src}?${compress}`; 23 + return `${src}?${compress}`
24 } 24 }
25 - return src; 25 + return src
26 } 26 }
27 27
28 /** 28 /**
...@@ -41,30 +41,30 @@ function normalize_image_url(src) { ...@@ -41,30 +41,30 @@ function normalize_image_url(src) {
41 * @param {string} params.imgUrl 分享图标地址 41 * @param {string} params.imgUrl 分享图标地址
42 * @returns {void} 42 * @returns {void}
43 */ 43 */
44 -export const sharePage = ({ title = '美乐爱觉', desc = '', imgUrl = '' }) => { 44 +export const sharePage = ({ title = '生命力教育联盟', desc = '', imgUrl = '' }) => {
45 const shareData = { 45 const shareData = {
46 title, // 分享标题 46 title, // 分享标题
47 desc, // 分享描述 47 desc, // 分享描述
48 link: location.origin + location.pathname + location.hash, // 分享链接,需与公众号 JS 安全域名一致 48 link: location.origin + location.pathname + location.hash, // 分享链接,需与公众号 JS 安全域名一致
49 imgUrl: normalize_image_url(imgUrl), // 分享图标,按规则追加压缩参数 49 imgUrl: normalize_image_url(imgUrl), // 分享图标,按规则追加压缩参数
50 - success: function () { 50 + success() {
51 // 设置成功回调 51 // 设置成功回调
52 - } 52 + },
53 } 53 }
54 54
55 if (wx && typeof wx.ready === 'function') { 55 if (wx && typeof wx.ready === 'function') {
56 wx.ready(() => { 56 wx.ready(() => {
57 // 分享好友(微信好友或qq好友) 57 // 分享好友(微信好友或qq好友)
58 - wx.updateAppMessageShareData(shareData); 58 + wx.updateAppMessageShareData(shareData)
59 // 分享到朋友圈或qq空间 59 // 分享到朋友圈或qq空间
60 - wx.updateTimelineShareData(shareData); 60 + wx.updateTimelineShareData(shareData)
61 // 分享到腾讯微博 61 // 分享到腾讯微博
62 if (typeof wx.onMenuShareWeibo === 'function') { 62 if (typeof wx.onMenuShareWeibo === 'function') {
63 - wx.onMenuShareWeibo(shareData); 63 + wx.onMenuShareWeibo(shareData)
64 } 64 }
65 - }); 65 + })
66 } else { 66 } else {
67 // 微信 JSSDK 未初始化或未就绪,分享配置可能不会生效 67 // 微信 JSSDK 未初始化或未就绪,分享配置可能不会生效
68 - console.warn('微信 JSSDK 未就绪:分享配置可能未生效'); 68 + console.warn('微信 JSSDK 未就绪:分享配置可能未生效')
69 } 69 }
70 } 70 }
......
1 一、总则 1 一、总则
2 - 1、“美乐爱觉”软件及相关服务,系指杭州南风教育科技有限公司(以下简称“南方教育”)合法拥有并运营的、标注名称为“美乐爱觉”的客户端、网站(https://wxm.behalo.cc)、WAP、小程序、公众号等及相关网站向您提供的产品与服务(以下统称“美乐爱觉平台”)。《“ 美乐爱觉平台”用户服务协议》(以下称“本协议”)是您与公司就您下载、安装、注册、登录、使用(以下统称“使用”)美乐爱觉互联网平台终端,并获得美乐爱觉平台提供的相关服务所订立的协议。 2 + 1、“生命力教育联盟”软件及相关服务,系指杭州南风教育科技有限公司(以下简称“南方教育”)合法拥有并运营的、标注名称为“生命力教育联盟”的客户端、网站(https://wxm.behalo.cc)、WAP、小程序、公众号等及相关网站向您提供的产品与服务(以下统称“生命力教育联盟平台”)。《“ 生命力教育联盟平台”用户服务协议》(以下称“本协议”)是您与公司就您下载、安装、注册、登录、使用(以下统称“使用”)生命力教育联盟互联网平台终端,并获得生命力教育联盟平台提供的相关服务所订立的协议。
3 3
4 - 2、在此特别提醒您(以下或称“用户”)在注册成为美乐爱觉平台用户之前,应当认真阅读本《用户服务协议》(以下简称“协议”),确保您充分理解本协议中各条款,并选择接受或不接受本协议。其中,对于免除或限制责任条款等内容将以加粗形式提醒您注意,您应重点阅读。除非您接受本协议所有条款,否则您无权注册、登录或使用本协议所涉服务。您的注册、登录、使用等行为即视为您已充分阅读、理解并同意完全接受本协议的全部内容,用户应当受本协议的约束。如您未满18周岁,请您应在法定监护人的陪同下仔细阅读本协议并充分理解本协议,并征得法定监护人的同意后方可注册成为美乐爱觉平台用户。 4 + 2、在此特别提醒您(以下或称“用户”)在注册成为生命力教育联盟平台用户之前,应当认真阅读本《用户服务协议》(以下简称“协议”),确保您充分理解本协议中各条款,并选择接受或不接受本协议。其中,对于免除或限制责任条款等内容将以加粗形式提醒您注意,您应重点阅读。除非您接受本协议所有条款,否则您无权注册、登录或使用本协议所涉服务。您的注册、登录、使用等行为即视为您已充分阅读、理解并同意完全接受本协议的全部内容,用户应当受本协议的约束。如您未满18周岁,请您应在法定监护人的陪同下仔细阅读本协议并充分理解本协议,并征得法定监护人的同意后方可注册成为生命力教育联盟平台用户。
5 5
6 - 3、本协议约定美乐爱觉平台与用户之间关于“美乐爱觉平台”服务(以下简称“服务”)的权利义务。“用户”是指注册、登录、使用本服务的个人。本协议可由美乐爱觉平台随时更新,更新后的协议条款一旦公布即代替原来的协议条款,并将以弹窗或其他形式提醒用户。用户可在本APP中查阅最新版协议条款。在修改协议条款后,如您不接受修改后的条款,您也可以选择停止使用,美乐爱觉平台亦有权因此终止您的注册进程及服务使用。您继续使用美乐爱觉平台提供的服务,则视为您已充分理解最新协议,并同意作为本协议的一方当事人接受本协议以及其他与“美乐爱觉平台”软件及相关服务相关的协议和规则(包括但不限于《“美乐爱觉平台”隐私政策》)的约束。 6 + 3、本协议约定生命力教育联盟平台与用户之间关于“生命力教育联盟平台”服务(以下简称“服务”)的权利义务。“用户”是指注册、登录、使用本服务的个人。本协议可由生命力教育联盟平台随时更新,更新后的协议条款一旦公布即代替原来的协议条款,并将以弹窗或其他形式提醒用户。用户可在本APP中查阅最新版协议条款。在修改协议条款后,如您不接受修改后的条款,您也可以选择停止使用,生命力教育联盟平台亦有权因此终止您的注册进程及服务使用。您继续使用生命力教育联盟平台提供的服务,则视为您已充分理解最新协议,并同意作为本协议的一方当事人接受本协议以及其他与“生命力教育联盟平台”软件及相关服务相关的协议和规则(包括但不限于《“生命力教育联盟平台”隐私政策》)的约束。
7 7
8 二、账号注册 8 二、账号注册
9 - 1、"美乐爱觉平台"公众号、小程序、APP、网站等基础功能使用无需注册登录,部分涉及用户数据的功能在使用前需要注册一个“美乐爱觉平台”账号,经“美乐爱觉平台”注册系统完成注册程序并通过身份认证的用户即成为正式用户,可以获得本协议规定用户应当享有的一切权限;未经身份认证用户不享有任何使用权限。 9 + 1、"生命力教育联盟平台"公众号、小程序、APP、网站等基础功能使用无需注册登录,部分涉及用户数据的功能在使用前需要注册一个“生命力教育联盟平台”账号,经“生命力教育联盟平台”注册系统完成注册程序并通过身份认证的用户即成为正式用户,可以获得本协议规定用户应当享有的一切权限;未经身份认证用户不享有任何使用权限。
10 10
11 - 2、“美乐爱觉平台”账号可使用手机号码或第三方平台账户(微信、QQ、Appleid)绑定注册,请用户使用尚未与“美乐爱觉平台”账号绑定的账户,以及未被美乐爱觉平台根据本协议封禁的账户注册“美乐爱觉平台”账号。美乐爱觉平台可以根据用户需求或产品需要对账号注册和绑定的方式进行变更,而无须事先通知用户。 11 + 2、“生命力教育联盟平台”账号可使用手机号码或第三方平台账户(微信、QQ、Appleid)绑定注册,请用户使用尚未与“生命力教育联盟平台”账号绑定的账户,以及未被生命力教育联盟平台根据本协议封禁的账户注册“生命力教育联盟平台”账号。生命力教育联盟平台可以根据用户需求或产品需要对账号注册和绑定的方式进行变更,而无须事先通知用户。
12 12
13 - 3、如果注册申请者有被美乐爱觉平台封禁的先例或涉嫌虚假注册及滥用他人名义注册,及其他不能得到许可的理由,美乐爱觉平台将拒绝其注册申请。 13 + 3、如果注册申请者有被生命力教育联盟平台封禁的先例或涉嫌虚假注册及滥用他人名义注册,及其他不能得到许可的理由,生命力教育联盟平台将拒绝其注册申请。
14 - 4、在用户注册及使用本服务时,美乐爱觉平台需要搜集能识别用户身份的个人信息以便美乐爱觉平台可以在必要时联系用户,或为用户提供更好的使用体验。您同意美乐爱觉平台为向您提供服务而收集您的个人信息,美乐爱觉平台搜集的信息包括但不限于用户手机号码、第三方平台账户、昵称等用户同意授权的信息。美乐爱觉平台对这些信息的使用将受限于用户个人隐私信息保护的约束。 14 + 4、在用户注册及使用本服务时,生命力教育联盟平台需要搜集能识别用户身份的个人信息以便生命力教育联盟平台可以在必要时联系用户,或为用户提供更好的使用体验。您同意生命力教育联盟平台为向您提供服务而收集您的个人信息,生命力教育联盟平台搜集的信息包括但不限于用户手机号码、第三方平台账户、昵称等用户同意授权的信息。生命力教育联盟平台对这些信息的使用将受限于用户个人隐私信息保护的约束。
15 三、用户使用规则 15 三、用户使用规则
16 - 1、您理解并承诺,您所设置的帐号不得违反国家法律法规及“美乐爱觉平台”的相关规则,您的帐号名称、头像和简介等注册信息及其他个人信息中不得出现违法和不良信息,未经他人许可不得用他人名义(包括但不限于冒用他人姓名、名称、字号、头像等或采取其他足以让人引起混淆的方式)开设帐号,不得恶意注册“美乐爱觉平台”帐号(包括但不限于频繁注册、批量注册帐号等行为)。您在帐号注册及使用过程中需遵守相关法律法规,不得实施任何侵害国家利益、损害其他公民合法权益,有害社会道德风尚的行为。公司有权对您提交的注册信息进行审核。 16 + 1、您理解并承诺,您所设置的帐号不得违反国家法律法规及“生命力教育联盟平台”的相关规则,您的帐号名称、头像和简介等注册信息及其他个人信息中不得出现违法和不良信息,未经他人许可不得用他人名义(包括但不限于冒用他人姓名、名称、字号、头像等或采取其他足以让人引起混淆的方式)开设帐号,不得恶意注册“生命力教育联盟平台”帐号(包括但不限于频繁注册、批量注册帐号等行为)。您在帐号注册及使用过程中需遵守相关法律法规,不得实施任何侵害国家利益、损害其他公民合法权益,有害社会道德风尚的行为。公司有权对您提交的注册信息进行审核。
17 17
18 - 2、您有责任维护个人帐号、密码的安全性与保密性,并对您以注册帐号名义所从事的活动承担全部法律责任,包括但不限于您在“美乐爱觉平台”软件及相关服务上进行的任何数据修改、言论发表、款项支付等操作行为可能引起的一切法律责任。您应高度重视对帐号与密码的保密,在任何情况下不向他人透露帐号及密码。若发现他人未经许可使用您的帐号或发生其他任何安全漏洞问题时,您应当立即通知公司。 18 + 2、您有责任维护个人帐号、密码的安全性与保密性,并对您以注册帐号名义所从事的活动承担全部法律责任,包括但不限于您在“生命力教育联盟平台”软件及相关服务上进行的任何数据修改、言论发表、款项支付等操作行为可能引起的一切法律责任。您应高度重视对帐号与密码的保密,在任何情况下不向他人透露帐号及密码。若发现他人未经许可使用您的帐号或发生其他任何安全漏洞问题时,您应当立即通知公司。
19 19
20 - 3、用户同意:美乐爱觉在提供服务的过程中以各种方式投放推广信息(包括但不限于:电子邮件、网站联络方式、在美乐爱觉平台的任何位置上投放),用户同意接受美乐爱觉以上述方式向用户发送推广信息。 20 + 3、用户同意:生命力教育联盟在提供服务的过程中以各种方式投放推广信息(包括但不限于:电子邮件、网站联络方式、在生命力教育联盟平台的任何位置上投放),用户同意接受生命力教育联盟以上述方式向用户发送推广信息。
21 四、账户安全 21 四、账户安全
22 - 1、用户一旦注册成功,成为美乐爱觉平台的用户,将有权利使用自己的用户名及密码随时登陆美乐爱觉平台。 22 + 1、用户一旦注册成功,成为生命力教育联盟平台的用户,将有权利使用自己的用户名及密码随时登陆生命力教育联盟平台。
23 2、用户对用户名和密码的安全负责,同时对以其账户进行的所有活动和事件负全部责任。 23 2、用户对用户名和密码的安全负责,同时对以其账户进行的所有活动和事件负全部责任。
24 - 3、用户不得以任何形式擅自转让或授权他人使用自己的美乐爱觉平台账户。 24 + 3、用户不得以任何形式擅自转让或授权他人使用自己的生命力教育联盟平台账户。
25 - 4、如果用户泄漏了账户密码,或用户发现任何人未经授权使用您的账号和密码的情况,应当立即修改密码并与美乐爱觉平台客服人员取得联系,并授权美乐爱觉平台暂停提供服务及展开调查,根据调查结果作出相应处理。用户理解美乐爱觉平台根据用户请求采取行动需要合理时间,美乐爱觉平台对采取行动前已经产生的后果和损失不承担任何责任。 25 + 4、如果用户泄漏了账户密码,或用户发现任何人未经授权使用您的账号和密码的情况,应当立即修改密码并与生命力教育联盟平台客服人员取得联系,并授权生命力教育联盟平台暂停提供服务及展开调查,根据调查结果作出相应处理。用户理解生命力教育联盟平台根据用户请求采取行动需要合理时间,生命力教育联盟平台对采取行动前已经产生的后果和损失不承担任何责任。
26 26
27 - 5、用户若发现任何非法使用用户账号或存在安全漏洞的情况,请立即通知美乐爱觉平台工作人员。 27 + 5、用户若发现任何非法使用用户账号或存在安全漏洞的情况,请立即通知生命力教育联盟平台工作人员。
28 - 6、因黑客行为或用户的保管疏忽导致账号非法使用,“美乐爱觉平台”不承担任何责任。 28 + 6、因黑客行为或用户的保管疏忽导致账号非法使用,“生命力教育联盟平台”不承担任何责任。
29 五、用户声明与保证 29 五、用户声明与保证
30 1、用户承诺其为具有完全民事行为能力的民事主体,且具有履行本协议约定义务的能力。 30 1、用户承诺其为具有完全民事行为能力的民事主体,且具有履行本协议约定义务的能力。
31 - 2、用户保证其为履行本协议而向美乐爱觉平台提供的全部资料均真实、有效。用户有义务在注册时提供自己的真实身份信息,并保证诸如手机号码、姓名等必要身份信息的有效性及安全性,保证美乐爱觉平台工作人员可以通过上述联系方式与用户取得联系。同时,用户也有义务在相关身份信息实际变更时及时更新有关注册资料。 31 + 2、用户保证其为履行本协议而向生命力教育联盟平台提供的全部资料均真实、有效。用户有义务在注册时提供自己的真实身份信息,并保证诸如手机号码、姓名等必要身份信息的有效性及安全性,保证生命力教育联盟平台工作人员可以通过上述联系方式与用户取得联系。同时,用户也有义务在相关身份信息实际变更时及时更新有关注册资料。
32 32
33 - 3、用户在使用美乐爱觉平台账号或本服务的过程中所制作、上载、复制、发布、传播的任何内容,不得违反国家相关法律制度,包括但不限于: 33 + 3、用户在使用生命力教育联盟平台账号或本服务的过程中所制作、上载、复制、发布、传播的任何内容,不得违反国家相关法律制度,包括但不限于:
34 (1)反对宪法所确定的基本原则的; 34 (1)反对宪法所确定的基本原则的;
35 (2)危害国家安全,泄露国家秘密,颠覆国家政权,破坏国家统一的; 35 (2)危害国家安全,泄露国家秘密,颠覆国家政权,破坏国家统一的;
36 (3)损害国家荣誉和利益的; 36 (3)损害国家荣誉和利益的;
...@@ -42,68 +42,68 @@ ...@@ -42,68 +42,68 @@
42 (9)煽动非法集会、结社、游行、示威、聚众扰乱社会秩序的; 42 (9)煽动非法集会、结社、游行、示威、聚众扰乱社会秩序的;
43 (10)以非法民间组织名义活动的; 43 (10)以非法民间组织名义活动的;
44 (11)含有法律、行政法规禁止的其他内容的。 44 (11)含有法律、行政法规禁止的其他内容的。
45 - 4、用户不得利用美乐爱觉平台账号或本服务制作、上载、复制、发布、传播任何干扰美乐爱觉平台正常运营,以及侵犯其他用户或第三方合法权益的内容,包括但不限于: 45 + 4、用户不得利用生命力教育联盟平台账号或本服务制作、上载、复制、发布、传播任何干扰生命力教育联盟平台正常运营,以及侵犯其他用户或第三方合法权益的内容,包括但不限于:
46 (1)含有任何性或性暗示的; 46 (1)含有任何性或性暗示的;
47 (2)含有辱骂、恐吓、威胁内容的; 47 (2)含有辱骂、恐吓、威胁内容的;
48 (3)含有骚扰、垃圾广告、恶意信息、诱骗信息的; 48 (3)含有骚扰、垃圾广告、恶意信息、诱骗信息的;
49 (4)涉及他人隐私、个人信息或资料的; 49 (4)涉及他人隐私、个人信息或资料的;
50 (5)侵害他人名誉权、肖像权、知识产权、商业秘密等合法权利的; 50 (5)侵害他人名誉权、肖像权、知识产权、商业秘密等合法权利的;
51 (6)含有其他干扰本服务正常运营和侵犯其他用户或第三方合法权益内容的信息。 51 (6)含有其他干扰本服务正常运营和侵犯其他用户或第三方合法权益内容的信息。
52 - 5、用户承若对其发表或者上传美乐爱觉平台的所有信息均享有完整的知识产权,或者已经得到相关权利人的合法授权,如用户违反本条规定造成美乐爱觉平台被第三人索赔的,用户应全额赔偿美乐爱觉平台一切损失费用(包括但不限于各种赔偿费、律师代理费、诉讼费及为此支出的其他合理费用)。 52 + 5、用户承若对其发表或者上传生命力教育联盟平台的所有信息均享有完整的知识产权,或者已经得到相关权利人的合法授权,如用户违反本条规定造成生命力教育联盟平台被第三人索赔的,用户应全额赔偿生命力教育联盟平台一切损失费用(包括但不限于各种赔偿费、律师代理费、诉讼费及为此支出的其他合理费用)。
53 53
54 - 6、当第三人认为用户发表或上传美乐爱觉平台的信息侵犯其权利,并根据相关法律法规向美乐爱觉平台发送权利通知书时,用户同意美乐爱觉平台可以自行判断决定删除涉嫌侵权信息,除非用户提交书面证据材料排除侵权的可能性,美乐爱觉平台不会自动回复上述删除信息。 54 + 6、当第三人认为用户发表或上传生命力教育联盟平台的信息侵犯其权利,并根据相关法律法规向生命力教育联盟平台发送权利通知书时,用户同意生命力教育联盟平台可以自行判断决定删除涉嫌侵权信息,除非用户提交书面证据材料排除侵权的可能性,生命力教育联盟平台不会自动回复上述删除信息。
55 55
56 六、服务内容 56 六、服务内容
57 - 1、美乐爱觉平台具体服务内容由美乐爱觉平台根据实际情况提供,包括但不限于:知识文章、视频课程等。具体以美乐爱觉平台实际提供的功能或服务为准。 57 + 1、生命力教育联盟平台具体服务内容由生命力教育联盟平台根据实际情况提供,包括但不限于:知识文章、视频课程等。具体以生命力教育联盟平台实际提供的功能或服务为准。
58 - 2、用户认可,美乐爱觉平台发给用户的所有通知、公告及其他消息都可通过用户所提供的联系方式向用户送达或通知。 58 + 2、用户认可,生命力教育联盟平台发给用户的所有通知、公告及其他消息都可通过用户所提供的联系方式向用户送达或通知。
59 七、付费课程相关 59 七、付费课程相关
60 - 美乐爱觉平台提供中华传统国学相关付费视频课程,视频课程属于虚拟计算机软件类商品。根据《消费者权益保护法》第二十五条规定,计算机软件等数字化商品不支持7天无理由退款,故当你购买付费服务成功后,不支持无条件退款。 60 + 生命力教育联盟平台提供中华传统国学相关付费视频课程,视频课程属于虚拟计算机软件类商品。根据《消费者权益保护法》第二十五条规定,计算机软件等数字化商品不支持7天无理由退款,故当你购买付费服务成功后,不支持无条件退款。
61 61
62 视频课程知识产权归本公司所有,用户付费购买的视频,用户仅享有播放权,不具备视频下载、视频剪辑等、视频传播等其他权利,若未经“杭州南风教育科技有限公司”许可,进行视频下载、视频剪辑等行为,本公司将依法追究其违法行为。 62 视频课程知识产权归本公司所有,用户付费购买的视频,用户仅享有播放权,不具备视频下载、视频剪辑等、视频传播等其他权利,若未经“杭州南风教育科技有限公司”许可,进行视频下载、视频剪辑等行为,本公司将依法追究其违法行为。
63 63
64 八、服务的暂停或终止 64 八、服务的暂停或终止
65 - 1、在下列情况下,美乐爱觉平台有权视具体情况自主决定暂停或终止向用户提供服务: 65 + 1、在下列情况下,生命力教育联盟平台有权视具体情况自主决定暂停或终止向用户提供服务:
66 - (1)在用户违反本服务协议相关规定时,美乐爱觉平台有权视具体情况自主决定暂停或终止向该用户提供服务。 66 + (1)在用户违反本服务协议相关规定时,生命力教育联盟平台有权视具体情况自主决定暂停或终止向该用户提供服务。
67 67
68 - (2)如美乐爱觉平台通过用户提供的信息与用户联系时,发现用户在注册时绑定的联系方式已不存在或无法与用户取得联系的,美乐爱觉平台将以系统通知的方式告知用户更改,如用户在三个工作日内仍未能提供新的联系方式,美乐爱觉平台有权终止向该用户提供服务。 68 + (2)如生命力教育联盟平台通过用户提供的信息与用户联系时,发现用户在注册时绑定的联系方式已不存在或无法与用户取得联系的,生命力教育联盟平台将以系统通知的方式告知用户更改,如用户在三个工作日内仍未能提供新的联系方式,生命力教育联盟平台有权终止向该用户提供服务。
69 69
70 (3)本服务条款终止或更新时,用户明示不愿接受新的服务条款的。 70 (3)本服务条款终止或更新时,用户明示不愿接受新的服务条款的。
71 - (4)用户主动注销账户或用户向美乐爱觉平台申请注销其账户,经美乐爱觉平台审核同意的。 71 + (4)用户主动注销账户或用户向生命力教育联盟平台申请注销其账户,经生命力教育联盟平台审核同意的。
72 - (5)其他美乐爱觉平台认为需终止服务的情况。 72 + (5)其他生命力教育联盟平台认为需终止服务的情况。
73 73
74 2、用户理解并同意: 74 2、用户理解并同意:
75 - (1)服务终止后,美乐爱觉平台没有义务为用户保留原账号中或与之相关的任何信息,或转发任何未曾阅读或发送的信息给用户或第三方。 75 + (1)服务终止后,生命力教育联盟平台没有义务为用户保留原账号中或与之相关的任何信息,或转发任何未曾阅读或发送的信息给用户或第三方。
76 - (2)用户在使用本服务期间存在违法行为或违反本协议行为的,美乐爱觉平台仍可依据本协议想用户主张权利或依法依规向行政、司法等机关进行披露。 76 + (2)用户在使用本服务期间存在违法行为或违反本协议行为的,生命力教育联盟平台仍可依据本协议想用户主张权利或依法依规向行政、司法等机关进行披露。
77 (3)用户在使用本服务期间与其他第三方(如有)之间发生的关系,不因本服务或本协议的终止而终止,第三方仍有权向用户主张权利,用户应继续向第三方履行相关义务。 77 (3)用户在使用本服务期间与其他第三方(如有)之间发生的关系,不因本服务或本协议的终止而终止,第三方仍有权向用户主张权利,用户应继续向第三方履行相关义务。
78 - 3、美乐爱觉平台保有删除APP内各类不符合法律政策或者不实信息内容而无须通知用户的权利。 78 + 3、生命力教育联盟平台保有删除APP内各类不符合法律政策或者不实信息内容而无须通知用户的权利。
79 - 4、若用户未遵守本协议规定的或其他服务条件的行为,美乐爱觉平台有权作出独立判断并采取暂停或关闭用户账号等措施,对于因此而造成用户无法正常使用账号及相关服务、无法正常获取用户账号内权益的等,美乐爱觉平台不承担任何责任。用户须对自己在网上的言论和行为承担法律责任。对于涉嫌违反法律法规、涉嫌违法犯罪的行为、美乐爱觉平台将保存有关记录,并有权依法向有关主管部门报告、配合有关主管部门调查、向公安机关报案等。 79 + 4、若用户未遵守本协议规定的或其他服务条件的行为,生命力教育联盟平台有权作出独立判断并采取暂停或关闭用户账号等措施,对于因此而造成用户无法正常使用账号及相关服务、无法正常获取用户账号内权益的等,生命力教育联盟平台不承担任何责任。用户须对自己在网上的言论和行为承担法律责任。对于涉嫌违反法律法规、涉嫌违法犯罪的行为、生命力教育联盟平台将保存有关记录,并有权依法向有关主管部门报告、配合有关主管部门调查、向公安机关报案等。
80 80
81 九、服务的变更、中断 81 九、服务的变更、中断
82 - 1、用户理解并同意,美乐爱觉平台提供的服务是按照现有技术和条件所能达到的现状提供的。用户亦明确知道使用服务存在一定信息风险,美乐爱觉平台将尽力维护用户使用服务的合法权益,但不担保服务一定能满足用户要求,也不担保服务的及时性、安全性、真实性、稳定性、正确性,对用户使用服务中出现的信息(包括但不限于用户发布的信息删除或存储失败),美乐爱觉平台为此不承担任何责任。 82 + 1、用户理解并同意,生命力教育联盟平台提供的服务是按照现有技术和条件所能达到的现状提供的。用户亦明确知道使用服务存在一定信息风险,生命力教育联盟平台将尽力维护用户使用服务的合法权益,但不担保服务一定能满足用户要求,也不担保服务的及时性、安全性、真实性、稳定性、正确性,对用户使用服务中出现的信息(包括但不限于用户发布的信息删除或存储失败),生命力教育联盟平台为此不承担任何责任。
83 83
84 - 2、用户理解并同意,美乐爱觉平台为了整体服务运营安全需要或定期或不定期地检测或者更新需要,有权视具体情况决定服务变更、中断、中止或终止服务,但美乐爱觉平台将尽可能事先进行通告。 84 + 2、用户理解并同意,生命力教育联盟平台为了整体服务运营安全需要或定期或不定期地检测或者更新需要,有权视具体情况决定服务变更、中断、中止或终止服务,但生命力教育联盟平台将尽可能事先进行通告。
85 - 3、用户理解并同意,鉴于网络服务的特殊性,服务可能会受到多种因素(包括但不限于境内外基础运营商的网络故障、技术缺陷、覆盖范围限制、不可抗力、计算机病毒、黑客攻击或其他非美乐爱觉平台技术能力范围内的事因等)的影响或干扰,美乐爱觉平台不能随时或始终预见和防范上述因素造成的服务中断、用户存储信息丢失、未保存、出现乱码、错误接收、无法接收、延迟接收等,美乐爱觉平台无需为此对任何用户或任何第三方承担责任。若发生上述因此,美乐爱觉平台将尽可能及时通过公告、系统通知等其他合理方式通知受到影响的用户。 85 + 3、用户理解并同意,鉴于网络服务的特殊性,服务可能会受到多种因素(包括但不限于境内外基础运营商的网络故障、技术缺陷、覆盖范围限制、不可抗力、计算机病毒、黑客攻击或其他非生命力教育联盟平台技术能力范围内的事因等)的影响或干扰,生命力教育联盟平台不能随时或始终预见和防范上述因素造成的服务中断、用户存储信息丢失、未保存、出现乱码、错误接收、无法接收、延迟接收等,生命力教育联盟平台无需为此对任何用户或任何第三方承担责任。若发生上述因此,生命力教育联盟平台将尽可能及时通过公告、系统通知等其他合理方式通知受到影响的用户。
86 86
87 十、知识产权条款 87 十、知识产权条款
88 - 1、北京美乐爱觉有限公司对本服务中所有内容,包括但不限于设计、画面安排、软件架构、图片、文章、视频等均由北京美乐爱觉有限公司依法拥有其知识产权(包括但不限于商标权、专利权、著作权、商业秘密等)。 88 + 1、北京生命力教育联盟有限公司对本服务中所有内容,包括但不限于设计、画面安排、软件架构、图片、文章、视频等均由北京生命力教育联盟有限公司依法拥有其知识产权(包括但不限于商标权、专利权、著作权、商业秘密等)。
89 - 2、非经北京美乐爱觉有限公司书面同意,任何人不得擅自使用、修改、复制、公开传播、改变、散布、发行或公开发表美乐爱觉平台程序或内容。 89 + 2、非经北京生命力教育联盟有限公司书面同意,任何人不得擅自使用、修改、复制、公开传播、改变、散布、发行或公开发表生命力教育联盟平台程序或内容。
90 3、尊重知识产权是用户应尽的义务,如有违反,应承担相应赔偿责任。 90 3、尊重知识产权是用户应尽的义务,如有违反,应承担相应赔偿责任。
91 十一、服务条款修改 91 十一、服务条款修改
92 - 1、美乐爱觉平台有权随时修改本服务条款的任何内容,一旦本服务条款的任何内容发生变动,美乐爱觉平台将会通过适当方式(包括但不限于弹窗)向用户提示修改内容。 92 + 1、生命力教育联盟平台有权随时修改本服务条款的任何内容,一旦本服务条款的任何内容发生变动,生命力教育联盟平台将会通过适当方式(包括但不限于弹窗)向用户提示修改内容。
93 - 2、如果不同意美乐爱觉平台对本服务条款所做的修改,用户有权停止使用本服务。 93 + 2、如果不同意生命力教育联盟平台对本服务条款所做的修改,用户有权停止使用本服务。
94 - 3、如果用户继续使用网络服务,则视为用户接受美乐爱觉平台对本服务条款所做的修改。 94 + 3、如果用户继续使用网络服务,则视为用户接受生命力教育联盟平台对本服务条款所做的修改。
95 十二、隐私保护 95 十二、隐私保护
96 请阅读《隐私保护政策》。 96 请阅读《隐私保护政策》。
97 十三、其他 97 十三、其他
98 - 1、若美乐爱觉平台已经明示其服务提供方式发生变更并提醒用户应当注意事项,用户未按要求操作所产生的一切后果由用户自行承担。 98 + 1、若生命力教育联盟平台已经明示其服务提供方式发生变更并提醒用户应当注意事项,用户未按要求操作所产生的一切后果由用户自行承担。
99 - 2、用户同意保障和维护美乐爱觉平台及其他用户的利益,由于用户在使用美乐爱觉平台有违法、不真实、不正当、侵犯第三方合法权益的行为,或用户违反本协议项下的任何条款而给美乐爱觉平台及任何其他第三方造成损失,用户同意承担由此造成的损害赔偿责任。 99 + 2、用户同意保障和维护生命力教育联盟平台及其他用户的利益,由于用户在使用生命力教育联盟平台有违法、不真实、不正当、侵犯第三方合法权益的行为,或用户违反本协议项下的任何条款而给生命力教育联盟平台及任何其他第三方造成损失,用户同意承担由此造成的损害赔偿责任。
100 100
101 - 3、本协议的效力、解释及纠纷的解决,适用于中华人民共和国法律。若用户和美乐爱觉平台之间发生任何纠纷或争议,首先应友好协商解决,协商不成的,任何一方均有权向杭州南风教育科技有限公司住所地人民法院提起诉讼。 101 + 3、本协议的效力、解释及纠纷的解决,适用于中华人民共和国法律。若用户和生命力教育联盟平台之间发生任何纠纷或争议,首先应友好协商解决,协商不成的,任何一方均有权向杭州南风教育科技有限公司住所地人民法院提起诉讼。
102 102
103 4、本协议的任何条款被司法部门认定为无效或不具可执行性,或违反所须适用的法律的,则该条款将被视为无效,其余条款仍然有效,对双方具有约束力。 103 4、本协议的任何条款被司法部门认定为无效或不具可执行性,或违反所须适用的法律的,则该条款将被视为无效,其余条款仍然有效,对双方具有约束力。
104 5、本协议最终解释权归杭州南风教育科技有限公司所有。 104 5、本协议最终解释权归杭州南风教育科技有限公司所有。
105 十四、免责声明 105 十四、免责声明
106 - 1、用户明确同意其使用美乐爱觉平台服务,以及对美乐爱觉平台服务加以依赖所存在的全部责任和风险将完全有其自己承担,因其使用美乐爱觉平台服务过程的行为,以及因此而产生的一切后果也由其自己承担,美乐爱觉平台对用户不承担任何责任。 106 + 1、用户明确同意其使用生命力教育联盟平台服务,以及对生命力教育联盟平台服务加以依赖所存在的全部责任和风险将完全有其自己承担,因其使用生命力教育联盟平台服务过程的行为,以及因此而产生的一切后果也由其自己承担,生命力教育联盟平台对用户不承担任何责任。
107 107
108 - 2、美乐爱觉平台不担保服务一定能满足用户要求,也不担保服务不会中断,对服务的及时性、安全性、准确性也都不作担保。
109 - 3、用户因使用本服务而产生的任何间接的、附带的、特殊的、结果性的或惩戒性的损害,美乐爱觉平台概不负责,均由用户自行承担。
...\ No newline at end of file ...\ No newline at end of file
108 + 2、生命力教育联盟平台不担保服务一定能满足用户要求,也不担保服务不会中断,对服务的及时性、安全性、准确性也都不作担保。
109 + 3、用户因使用本服务而产生的任何间接的、附带的、特殊的、结果性的或惩戒性的损害,生命力教育联盟平台概不负责,均由用户自行承担。
......
...@@ -23,7 +23,7 @@ export const routes = [ ...@@ -23,7 +23,7 @@ export const routes = [
23 path: '/', 23 path: '/',
24 name: 'HomePage', 24 name: 'HomePage',
25 component: () => import('../views/HomePage.vue'), 25 component: () => import('../views/HomePage.vue'),
26 - meta: { title: '美乐爱觉' }, 26 + meta: { title: '生命力教育联盟' },
27 }, 27 },
28 { 28 {
29 path: '/courses', 29 path: '/courses',
...@@ -158,7 +158,7 @@ export const routes = [ ...@@ -158,7 +158,7 @@ export const routes = [
158 path: '/recall/choose', 158 path: '/recall/choose',
159 name: 'ChoosePage', 159 name: 'ChoosePage',
160 component: () => import('../views/recall/ChoosePage.vue'), 160 component: () => import('../views/recall/ChoosePage.vue'),
161 - meta: { title: '美乐爱觉AI星球' }, 161 + meta: { title: '生命力教育联盟AI星球' },
162 }, 162 },
163 { 163 {
164 path: '/checkout', 164 path: '/checkout',
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 * @LastEditTime: 2026-01-20 16:30:23 4 * @LastEditTime: 2026-01-20 16:30:23
5 * @FilePath: /mlaj/src/views/HomePage.vue 5 * @FilePath: /mlaj/src/views/HomePage.vue
6 - * @Description: 美乐爱觉教育首页组件 6 + * @Description: 生命力教育联盟教育首页组件
7 * 7 *
8 * 主要功能模块: 8 * 主要功能模块:
9 * 1. 用户欢迎区:显示用户信息和每日打卡 9 * 1. 用户欢迎区:显示用户信息和每日打卡
...@@ -29,18 +29,23 @@ ...@@ -29,18 +29,23 @@
29 --> 29 -->
30 30
31 <template> 31 <template>
32 - <AppLayout title="美乐爱觉教育"> 32 + <AppLayout title="生命力教育联盟教育">
33 <div class="bg-gradient-to-b from-white via-green-50/10 to-blue-50/10"> 33 <div class="bg-gradient-to-b from-white via-green-50/10 to-blue-50/10">
34 <!-- Header Section with Welcome & Weather --> 34 <!-- Header Section with Welcome & Weather -->
35 - <div v-if="currentUser" class="px-4 pt-3 pb-4"> 35 + <div v-if="currentUser" class="px-4 pb-4 pt-3">
36 - <FrostedGlass class="p-4 rounded-xl mb-4"> 36 + <FrostedGlass class="mb-4 rounded-xl p-4">
37 - <div class="flex justify-between items-center mb-3"> 37 + <div class="mb-3 flex items-center justify-between">
38 <div class="flex items-center"> 38 <div class="flex items-center">
39 - <div class="w-10 h-10 rounded-full overflow-hidden mr-3"> 39 + <div class="mr-3 h-10 w-10 overflow-hidden rounded-full">
40 <img 40 <img
41 - :src="buildCdnImageUrl(currentUser?.avatar || 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg')" 41 + :src="
42 - class="w-full h-full object-cover" 42 + buildCdnImageUrl(
43 - @error="handleImageError" /> 43 + currentUser?.avatar || 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg'
44 + )
45 + "
46 + class="h-full w-full object-cover"
47 + @error="handleImageError"
48 + />
44 </div> 49 </div>
45 <div> 50 <div>
46 <h2 class="text-xl font-bold">欢迎回来,{{ currentUser.name || '登录用户' }}!</h2> 51 <h2 class="text-xl font-bold">欢迎回来,{{ currentUser.name || '登录用户' }}!</h2>
...@@ -57,25 +62,25 @@ ...@@ -57,25 +62,25 @@
57 </div> 62 </div>
58 63
59 <!-- User Stats --> 64 <!-- User Stats -->
60 - <div class="flex justify-between text-center py-2"> 65 + <div class="flex justify-between py-2 text-center">
61 - <div class=" border-gray-200 flex-1"> 66 + <div class="flex-1 border-gray-200">
62 - <div class="text-lg font-bold flex items-baseline justify-center"> 67 + <div class="flex items-baseline justify-center text-lg font-bold">
63 <span>{{ currentUser?.total_days || 0 }}</span> 68 <span>{{ currentUser?.total_days || 0 }}</span>
64 - <span class="text-xs ml-1 font-normal">天</span> 69 + <span class="ml-1 text-xs font-normal">天</span>
65 </div> 70 </div>
66 <div class="text-xs text-gray-500">累计打卡</div> 71 <div class="text-xs text-gray-500">累计打卡</div>
67 </div> 72 </div>
68 - <div class="border-gray-200 flex-1"> 73 + <div class="flex-1 border-gray-200">
69 - <div class="text-lg font-bold flex items-baseline justify-center"> 74 + <div class="flex items-baseline justify-center text-lg font-bold">
70 <span>{{ currentUser?.consecutive_days || 0 }}</span> 75 <span>{{ currentUser?.consecutive_days || 0 }}</span>
71 - <span class="text-xs ml-1 font-normal">天</span> 76 + <span class="ml-1 text-xs font-normal">天</span>
72 </div> 77 </div>
73 <div class="text-xs text-gray-500">连续打卡</div> 78 <div class="text-xs text-gray-500">连续打卡</div>
74 </div> 79 </div>
75 - <div class="border-gray-200 flex-1"> 80 + <div class="flex-1 border-gray-200">
76 - <div class="text-lg font-bold flex items-baseline justify-center"> 81 + <div class="flex items-baseline justify-center text-lg font-bold">
77 <span>{{ currentUser?.longest_consecutive_days || 0 }}</span> 82 <span>{{ currentUser?.longest_consecutive_days || 0 }}</span>
78 - <span class="text-xs ml-1 font-normal">天</span> 83 + <span class="ml-1 text-xs font-normal">天</span>
79 </div> 84 </div>
80 <div class="text-xs text-gray-500">最长连续</div> 85 <div class="text-xs text-gray-500">最长连续</div>
81 </div> 86 </div>
...@@ -83,13 +88,19 @@ ...@@ -83,13 +88,19 @@
83 </FrostedGlass> 88 </FrostedGlass>
84 89
85 <!-- Daily Check-in --> 90 <!-- Daily Check-in -->
86 - <FrostedGlass class="p-4 rounded-xl"> 91 + <FrostedGlass class="rounded-xl p-4">
87 - <div class="flex justify-between items-center mb-3"> 92 + <div class="mb-3 flex items-center justify-between">
88 <h3 class="font-medium">今日打卡</h3> 93 <h3 class="font-medium">今日打卡</h3>
89 - <router-link to="/profile" class="text-green-600 text-sm">打卡记录</router-link> 94 + <router-link to="/profile" class="text-sm text-green-600">打卡记录</router-link>
90 </div> 95 </div>
91 <template v-if="checkInTypes.length"> 96 <template v-if="checkInTypes.length">
92 - <CheckInList :items="checkInTypes" dense scroll :plain="true" @submit-success="handleHomeCheckInSuccess" /> 97 + <CheckInList
98 + :items="checkInTypes"
99 + dense
100 + scroll
101 + :plain="true"
102 + @submit-success="handleHomeCheckInSuccess"
103 + />
93 </template> 104 </template>
94 <template v-else> 105 <template v-else>
95 <div class="text-center"> 106 <div class="text-center">
...@@ -165,7 +176,7 @@ ...@@ -165,7 +176,7 @@
165 </div> --> 176 </div> -->
166 177
167 <!-- Content Based on Active Tab --> 178 <!-- Content Based on Active Tab -->
168 - <div class="px-4 mt-5" ref="contentRef"> 179 + <div class="mt-5 px-4" ref="contentRef">
169 <!-- Recommended Content --> 180 <!-- Recommended Content -->
170 <div v-if="activeTab === '推荐'"> 181 <div v-if="activeTab === '推荐'">
171 <RecommendationsSection /> 182 <RecommendationsSection />
...@@ -176,73 +187,85 @@ ...@@ -176,73 +187,85 @@
176 <!-- Live Content --> 187 <!-- Live Content -->
177 <div v-if="activeTab === '直播'"> 188 <div v-if="activeTab === '直播'">
178 <section> 189 <section>
179 - <div class="flex justify-between items-center mb-3"> 190 + <div class="mb-3 flex items-center justify-between">
180 <h3 class="font-medium">正在直播</h3> 191 <h3 class="font-medium">正在直播</h3>
181 - <div class="text-xs text-red-500 flex items-center"> 192 + <div class="flex items-center text-xs text-red-500">
182 - <div class="w-2 h-2 bg-red-500 rounded-full mr-1 animate-pulse"></div> 193 + <div class="mr-1 h-2 w-2 animate-pulse rounded-full bg-red-500"></div>
183 2个直播中 194 2个直播中
184 </div> 195 </div>
185 </div> 196 </div>
186 - <div class="grid grid-cols-2 gap-4 mb-7"> 197 + <div class="mb-7 grid grid-cols-2 gap-4">
187 - <LiveStreamCard 198 + <LiveStreamCard v-for="stream in liveStreams" :key="stream.id" :stream="stream" />
188 - v-for="stream in liveStreams"
189 - :key="stream.id"
190 - :stream="stream"
191 - />
192 </div> 199 </div>
193 200
194 <div class="mb-5"> 201 <div class="mb-5">
195 - <div class="flex justify-between items-center mb-3"> 202 + <div class="mb-3 flex items-center justify-between">
196 <h3 class="font-medium">直播日历</h3> 203 <h3 class="font-medium">直播日历</h3>
197 <router-link to="/live-calendar" class="text-xs text-blue-500"> 204 <router-link to="/live-calendar" class="text-xs text-blue-500">
198 查看日历 205 查看日历
199 </router-link> 206 </router-link>
200 </div> 207 </div>
201 - <FrostedGlass class="p-3 rounded-xl"> 208 + <FrostedGlass class="rounded-xl p-3">
202 <div class="flex space-x-2 overflow-x-auto py-1"> 209 <div class="flex space-x-2 overflow-x-auto py-1">
203 <div 210 <div
204 v-for="(day, i) in ['今天', '明天', '周三', '周四', '周五', '周六', '周日']" 211 v-for="(day, i) in ['今天', '明天', '周三', '周四', '周五', '周六', '周日']"
205 :key="day" 212 :key="day"
206 :class="[ 213 :class="[
207 - 'flex-shrink-0 w-10 h-14 flex flex-col items-center justify-center rounded-lg', 214 + 'flex h-14 w-10 flex-shrink-0 flex-col items-center justify-center rounded-lg',
208 - i === 0 ? 'bg-green-500 text-white' : 'bg-white/50' 215 + i === 0 ? 'bg-green-500 text-white' : 'bg-white/50',
209 ]" 216 ]"
210 > 217 >
211 <div class="text-xs">{{ day }}</div> 218 <div class="text-xs">{{ day }}</div>
212 - <div class="font-bold mt-1">{{ new Date().getDate() + i }}</div> 219 + <div class="mt-1 font-bold">{{ new Date().getDate() + i }}</div>
213 </div> 220 </div>
214 </div> 221 </div>
215 </FrostedGlass> 222 </FrostedGlass>
216 </div> 223 </div>
217 224
218 <div> 225 <div>
219 - <h3 class="font-medium mb-3">直播预告</h3> 226 + <h3 class="mb-3 font-medium">直播预告</h3>
220 <div class="space-y-3"> 227 <div class="space-y-3">
221 <FrostedGlass 228 <FrostedGlass
222 v-for="(item, index) in [ 229 v-for="(item, index) in [
223 - { title: '亲子阅读会第1期', time: '今天 19:30-20:30', image: 'https://cdn.ipadbiz.cn/mlaj/images/live-1.jpg' }, 230 + {
224 - { title: '儿童心理健康讲座', time: '明天 20:00-21:00', image: 'https://cdn.ipadbiz.cn/mlaj/images/live-2.jpg' }, 231 + title: '亲子阅读会第1期',
225 - { title: '家庭教育经验分享', time: '周三 19:00-20:00', image: 'https://cdn.ipadbiz.cn/mlaj/images/live-3.jpg' } 232 + time: '今天 19:30-20:30',
233 + image: 'https://cdn.ipadbiz.cn/mlaj/images/live-1.jpg',
234 + },
235 + {
236 + title: '儿童心理健康讲座',
237 + time: '明天 20:00-21:00',
238 + image: 'https://cdn.ipadbiz.cn/mlaj/images/live-2.jpg',
239 + },
240 + {
241 + title: '家庭教育经验分享',
242 + time: '周三 19:00-20:00',
243 + image: 'https://cdn.ipadbiz.cn/mlaj/images/live-3.jpg',
244 + },
226 ]" 245 ]"
227 :key="index" 246 :key="index"
228 - class="p-3 rounded-xl" 247 + class="rounded-xl p-3"
229 > 248 >
230 - <div class="flex justify-between items-center"> 249 + <div class="flex items-center justify-between">
231 <div class="flex items-center"> 250 <div class="flex items-center">
232 - <div class="w-12 h-12 bg-green-100 rounded-lg overflow-hidden mr-3 flex-shrink-0"> 251 + <div
252 + class="mr-3 h-12 w-12 flex-shrink-0 overflow-hidden rounded-lg bg-green-100"
253 + >
233 <img 254 <img
234 :src="buildCdnImageUrl(item.image)" 255 :src="buildCdnImageUrl(item.image)"
235 :alt="item.title" 256 :alt="item.title"
236 - class="w-full h-full object-cover" 257 + class="h-full w-full object-cover"
237 @error="handleImageError" 258 @error="handleImageError"
238 /> 259 />
239 </div> 260 </div>
240 <div> 261 <div>
241 - <h4 class="font-medium text-sm">{{ item.title }}</h4> 262 + <h4 class="text-sm font-medium">{{ item.title }}</h4>
242 - <p class="text-xs text-gray-500 mt-1">{{ item.time }}</p> 263 + <p class="mt-1 text-xs text-gray-500">{{ item.time }}</p>
243 </div> 264 </div>
244 </div> 265 </div>
245 - <button class="bg-white text-green-600 border border-green-600 px-3 py-1 rounded-full text-xs flex-shrink-0"> 266 + <button
267 + class="flex-shrink-0 rounded-full border border-green-600 bg-white px-3 py-1 text-xs text-green-600"
268 + >
246 预约 269 预约
247 </button> 270 </button>
248 </div> 271 </div>
...@@ -256,17 +279,19 @@ ...@@ -256,17 +279,19 @@
256 <div v-if="activeTab === '精选'"> 279 <div v-if="activeTab === '精选'">
257 <section> 280 <section>
258 <div class="mb-5"> 281 <div class="mb-5">
259 - <h3 class="font-medium mb-3">精选内容</h3> 282 + <h3 class="mb-3 font-medium">精选内容</h3>
260 - <FrostedGlass class="p-4 rounded-xl"> 283 + <FrostedGlass class="rounded-xl p-4">
261 <div class="flex flex-col"> 284 <div class="flex flex-col">
262 - <div class="inline-block px-2 py-1 bg-blue-100 text-blue-600 text-xs rounded-full mb-2 w-fit"> 285 + <div
286 + class="mb-2 inline-block w-fit rounded-full bg-blue-100 px-2 py-1 text-xs text-blue-600"
287 + >
263 独家专栏 288 独家专栏
264 </div> 289 </div>
265 - <h4 class="font-medium text-lg mb-2">《如何培养孩子的阅读习惯》</h4> 290 + <h4 class="mb-2 text-lg font-medium">《如何培养孩子的阅读习惯》</h4>
266 - <p class="text-gray-600 text-sm mb-4 line-clamp-2"> 291 + <p class="mb-4 line-clamp-2 text-sm text-gray-600">
267 阅读习惯的培养是一个长期过程,本文将分享如何从日常生活点滴培养孩子的阅读兴趣和习惯... 292 阅读习惯的培养是一个长期过程,本文将分享如何从日常生活点滴培养孩子的阅读兴趣和习惯...
268 </p> 293 </p>
269 - <router-link to="/articles/1" class="text-green-600 text-sm font-medium"> 294 + <router-link to="/articles/1" class="text-sm font-medium text-green-600">
270 查看完整文章 295 查看完整文章
271 </router-link> 296 </router-link>
272 </div> 297 </div>
...@@ -274,34 +299,68 @@ ...@@ -274,34 +299,68 @@
274 </div> 299 </div>
275 300
276 <div> 301 <div>
277 - <h3 class="font-medium mb-3">推荐视频</h3> 302 + <h3 class="mb-3 font-medium">推荐视频</h3>
278 <div class="space-y-4"> 303 <div class="space-y-4">
279 <div 304 <div
280 v-for="(item, index) in [ 305 v-for="(item, index) in [
281 - { title: '亲子沟通的艺术', views: '1.2万', duration: '08:25', image: 'https://cdn.ipadbiz.cn/mlaj/images/video-1.jpg', video_url: 'https://sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-360p.mp4' }, 306 + {
282 - { title: '如何做好家庭教育', views: '8千', duration: '12:40', image: 'https://cdn.ipadbiz.cn/mlaj/images/video-2.jpg', video_url: 'https://sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-360p.mp4' }, 307 + title: '亲子沟通的艺术',
283 - { title: '孩子营养餐制作指南', views: '5千', duration: '15:18', image: 'https://cdn.ipadbiz.cn/mlaj/images/video-3.jpg', video_url: 'https://sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-360p.mp4' } 308 + views: '1.2万',
309 + duration: '08:25',
310 + image: 'https://cdn.ipadbiz.cn/mlaj/images/video-1.jpg',
311 + video_url:
312 + 'https://sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-360p.mp4',
313 + },
314 + {
315 + title: '如何做好家庭教育',
316 + views: '8千',
317 + duration: '12:40',
318 + image: 'https://cdn.ipadbiz.cn/mlaj/images/video-2.jpg',
319 + video_url:
320 + 'https://sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-360p.mp4',
321 + },
322 + {
323 + title: '孩子营养餐制作指南',
324 + views: '5千',
325 + duration: '15:18',
326 + image: 'https://cdn.ipadbiz.cn/mlaj/images/video-3.jpg',
327 + video_url:
328 + 'https://sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-360p.mp4',
329 + },
284 ]" 330 ]"
285 :key="index" 331 :key="index"
286 - class="relative rounded-xl overflow-hidden shadow-md h-48" 332 + class="relative h-48 overflow-hidden rounded-xl shadow-md"
287 > 333 >
288 <template v-if="activeVideoIndex !== index"> 334 <template v-if="activeVideoIndex !== index">
289 <img 335 <img
290 :src="buildCdnImageUrl(item.image, 400)" 336 :src="buildCdnImageUrl(item.image, 400)"
291 :alt="item.title" 337 :alt="item.title"
292 - class="w-full h-full object-cover" 338 + class="h-full w-full object-cover"
293 @error="handleImageError" 339 @error="handleImageError"
294 /> 340 />
295 - <div class="absolute inset-0 bg-gradient-to-b from-transparent to-black/70 flex flex-col justify-end p-4"> 341 + <div
296 - <h4 class="text-white font-medium mb-1">{{ item.title }}</h4> 342 + class="absolute inset-0 flex flex-col justify-end bg-gradient-to-b from-transparent to-black/70 p-4"
297 - <div class="flex justify-between items-center"> 343 + >
298 - <p class="text-white/80 text-xs">{{ item.views }}次播放 · {{ item.duration }}</p> 344 + <h4 class="mb-1 font-medium text-white">{{ item.title }}</h4>
345 + <div class="flex items-center justify-between">
346 + <p class="text-xs text-white/80">
347 + {{ item.views }}次播放 · {{ item.duration }}
348 + </p>
299 <button 349 <button
300 - class="bg-white/20 backdrop-blur-sm p-2 rounded-full" 350 + class="rounded-full bg-white/20 p-2 backdrop-blur-sm"
301 @click="playVideo(index, item.video_url)" 351 @click="playVideo(index, item.video_url)"
302 > 352 >
303 - <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-white" viewBox="0 0 20 20" fill="currentColor"> 353 + <svg
304 - <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z" clip-rule="evenodd" /> 354 + xmlns="http://www.w3.org/2000/svg"
355 + class="h-5 w-5 text-white"
356 + viewBox="0 0 20 20"
357 + fill="currentColor"
358 + >
359 + <path
360 + fill-rule="evenodd"
361 + d="M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z"
362 + clip-rule="evenodd"
363 + />
305 </svg> 364 </svg>
306 </button> 365 </button>
307 </div> 366 </div>
...@@ -349,7 +408,7 @@ import { useHomeVideoPlayer } from '@/composables/useHomeVideoPlayer' ...@@ -349,7 +408,7 @@ import { useHomeVideoPlayer } from '@/composables/useHomeVideoPlayer'
349 import { useImageLoader } from '@/composables/useImageLoader' 408 import { useImageLoader } from '@/composables/useImageLoader'
350 409
351 // 导入接口 410 // 导入接口
352 -import { getTaskListAPI } from "@/api/checkin"; 411 +import { getTaskListAPI } from '@/api/checkin'
353 import { normalizeCheckinTaskItems, buildCdnImageUrl } from '@/utils/tools' 412 import { normalizeCheckinTaskItems, buildCdnImageUrl } from '@/utils/tools'
354 413
355 // 图片加载错误处理 414 // 图片加载错误处理
...@@ -369,16 +428,20 @@ const { currentUser } = useAuth() ...@@ -369,16 +428,20 @@ const { currentUser } = useAuth()
369 const activeTab = ref('推荐') // 当前激活的内容标签页 428 const activeTab = ref('推荐') // 当前激活的内容标签页
370 429
371 // 签到列表 430 // 签到列表
372 -const checkInTypes = ref([]); 431 +const checkInTypes = ref([])
373 432
374 onMounted(() => { 433 onMounted(() => {
375 - watch(() => currentUser.value, async (newVal) => { 434 + watch(
435 + () => currentUser.value,
436 + async newVal => {
376 if (!newVal) return 437 if (!newVal) return
377 const task = await getTaskListAPI() 438 const task = await getTaskListAPI()
378 if (task && task.code) { 439 if (task && task.code) {
379 checkInTypes.value = normalizeCheckinTaskItems(task.data) 440 checkInTypes.value = normalizeCheckinTaskItems(task.data)
380 } 441 }
381 - }, { immediate: true }) 442 + },
443 + { immediate: true }
444 + )
382 }) 445 })
383 446
384 // 工具函数:格式化今天的日期为中文格式 447 // 工具函数:格式化今天的日期为中文格式
...@@ -414,7 +477,7 @@ watch(activeTab, () => { ...@@ -414,7 +477,7 @@ watch(activeTab, () => {
414 const marginTop = parseInt(window.getComputedStyle(contentRef.value).marginTop) 477 const marginTop = parseInt(window.getComputedStyle(contentRef.value).marginTop)
415 window.scrollTo({ 478 window.scrollTo({
416 top: contentRef.value.offsetTop - navHeight - marginTop, 479 top: contentRef.value.offsetTop - navHeight - marginTop,
417 - behavior:'smooth' 480 + behavior: 'smooth',
418 }) 481 })
419 } 482 }
420 }) 483 })
......
1 <template> 1 <template>
2 - <div class="min-h-screen flex flex-col bg-gradient-to-br from-green-50 via-teal-50 to-blue-50 py-12 px-4 sm:px-6 lg:px-8"> 2 + <div
3 + class="flex min-h-screen flex-col bg-gradient-to-br from-green-50 via-teal-50 to-blue-50 px-4 py-12 sm:px-6 lg:px-8"
4 + >
3 <div class="sm:mx-auto sm:w-full sm:max-w-md"> 5 <div class="sm:mx-auto sm:w-full sm:max-w-md">
4 - <h1 class="text-center text-3xl font-bold text-gray-800 mb-2">美乐爱觉教育</h1> 6 + <h1 class="mb-2 text-center text-3xl font-bold text-gray-800">生命力教育联盟教育</h1>
5 <h2 class="text-center text-xl font-medium text-gray-600">重置密码</h2> 7 <h2 class="text-center text-xl font-medium text-gray-600">重置密码</h2>
6 </div> 8 </div>
7 9
8 <div class="mt-8 sm:mx-auto sm:w-full sm:max-w-md"> 10 <div class="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
9 - <FrostedGlass class="py-8 px-6 rounded-lg"> 11 + <FrostedGlass class="rounded-lg px-6 py-8">
10 - <div v-if="error" class="mb-4 bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded-md"> 12 + <div
13 + v-if="error"
14 + class="mb-4 rounded-md border border-red-400 bg-red-100 px-4 py-3 text-red-700"
15 + >
11 {{ error }} 16 {{ error }}
12 </div> 17 </div>
13 18
...@@ -25,7 +30,7 @@ ...@@ -25,7 +30,7 @@
25 maxlength="11" 30 maxlength="11"
26 @input="formData.phone = formData.phone.replace(/\D/g, '')" 31 @input="formData.phone = formData.phone.replace(/\D/g, '')"
27 @blur="validatePhone" 32 @blur="validatePhone"
28 - class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-green-500 focus:border-green-500" 33 + class="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-green-500 focus:outline-none focus:ring-green-500"
29 /> 34 />
30 </div> 35 </div>
31 36
...@@ -40,13 +45,13 @@ ...@@ -40,13 +45,13 @@
40 type="text" 45 type="text"
41 required 46 required
42 maxlength="6" 47 maxlength="6"
43 - class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-green-500 focus:border-green-500" 48 + class="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-green-500 focus:outline-none focus:ring-green-500"
44 /> 49 />
45 <button 50 <button
46 type="button" 51 type="button"
47 :disabled="countdown > 0 || !isPhoneValid" 52 :disabled="countdown > 0 || !isPhoneValid"
48 @click="sendVerificationCode" 53 @click="sendVerificationCode"
49 - class="mt-1 px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-green-600 hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500 disabled:opacity-50 disabled:cursor-not-allowed whitespace-nowrap" 54 + class="mt-1 whitespace-nowrap rounded-md border border-transparent bg-green-600 px-4 py-2 text-sm font-medium text-white hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
50 > 55 >
51 {{ countdown > 0 ? `${countdown}秒后重试` : '获取验证码' }} 56 {{ countdown > 0 ? `${countdown}秒后重试` : '获取验证码' }}
52 </button> 57 </button>
...@@ -63,7 +68,7 @@ ...@@ -63,7 +68,7 @@
63 type="password" 68 type="password"
64 required 69 required
65 minlength="6" 70 minlength="6"
66 - class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-green-500 focus:border-green-500" 71 + class="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-green-500 focus:outline-none focus:ring-green-500"
67 /> 72 />
68 </div> 73 </div>
69 74
...@@ -77,7 +82,7 @@ ...@@ -77,7 +82,7 @@
77 type="password" 82 type="password"
78 required 83 required
79 minlength="6" 84 minlength="6"
80 - class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-green-500 focus:border-green-500" 85 + class="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-green-500 focus:outline-none focus:ring-green-500"
81 /> 86 />
82 </div> 87 </div>
83 88
...@@ -85,15 +90,15 @@ ...@@ -85,15 +90,15 @@
85 <button 90 <button
86 type="submit" 91 type="submit"
87 :disabled="loading" 92 :disabled="loading"
88 - class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-gradient-to-r from-green-500 to-green-600 hover:from-green-600 hover:to-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500" 93 + class="flex w-full justify-center rounded-md border border-transparent bg-gradient-to-r from-green-500 to-green-600 px-4 py-2 text-sm font-medium text-white shadow-sm hover:from-green-600 hover:to-green-700 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2"
89 - :class="{ 'opacity-70 cursor-not-allowed': loading }" 94 + :class="{ 'cursor-not-allowed opacity-70': loading }"
90 > 95 >
91 {{ loading ? '提交中...' : '重置密码' }} 96 {{ loading ? '提交中...' : '重置密码' }}
92 </button> 97 </button>
93 </div> 98 </div>
94 </form> 99 </form>
95 100
96 - <div class="text-center mt-6"> 101 + <div class="mt-6 text-center">
97 <p class="text-sm text-gray-600"> 102 <p class="text-sm text-gray-600">
98 记起密码了? 103 记起密码了?
99 <router-link to="/login" class="font-medium text-green-600 hover:text-green-500"> 104 <router-link to="/login" class="font-medium text-green-600 hover:text-green-500">
...@@ -110,9 +115,9 @@ ...@@ -110,9 +115,9 @@
110 import { ref, reactive } from 'vue' 115 import { ref, reactive } from 'vue'
111 import { useRouter } from 'vue-router' 116 import { useRouter } from 'vue-router'
112 import FrostedGlass from '@/components/effects/FrostedGlass.vue' 117 import FrostedGlass from '@/components/effects/FrostedGlass.vue'
113 -import { smsAPI } from '@/api/common'; 118 +import { smsAPI } from '@/api/common'
114 -import { resetPasswordAPI } from '@/api/users'; 119 +import { resetPasswordAPI } from '@/api/users'
115 -import { showToast } from 'vant'; 120 +import { showToast } from 'vant'
116 121
117 const router = useRouter() 122 const router = useRouter()
118 const error = ref('') 123 const error = ref('')
...@@ -124,7 +129,7 @@ const formData = reactive({ ...@@ -124,7 +129,7 @@ const formData = reactive({
124 phone: '', 129 phone: '',
125 verificationCode: '', 130 verificationCode: '',
126 password: '', 131 password: '',
127 - confirmPassword: '' 132 + confirmPassword: '',
128 }) 133 })
129 134
130 const startCountdown = () => { 135 const startCountdown = () => {
...@@ -187,7 +192,7 @@ const handleSubmit = async () => { ...@@ -187,7 +192,7 @@ const handleSubmit = async () => {
187 const { code } = await resetPasswordAPI({ 192 const { code } = await resetPasswordAPI({
188 mobile: formData.phone, 193 mobile: formData.phone,
189 sms_code: formData.verificationCode, 194 sms_code: formData.verificationCode,
190 - password: formData.password 195 + password: formData.password,
191 }) 196 })
192 197
193 if (code === 1) { 198 if (code === 1) {
...@@ -195,7 +200,6 @@ const handleSubmit = async () => { ...@@ -195,7 +200,6 @@ const handleSubmit = async () => {
195 // 重置成功后跳转到登录页 200 // 重置成功后跳转到登录页
196 router.push('/login') 201 router.push('/login')
197 } 202 }
198 -
199 } catch (err) { 203 } catch (err) {
200 console.error('Reset password error:', err) 204 console.error('Reset password error:', err)
201 error.value = '重置密码失败,请稍后重试' 205 error.value = '重置密码失败,请稍后重试'
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
8 size="10rem" 8 size="10rem"
9 style="margin-bottom: 0.5rem" 9 style="margin-bottom: 0.5rem"
10 /> 10 />
11 - <h1 class="mb-2 text-center text-3xl font-bold text-gray-800">美乐爱觉教育</h1> 11 + <h1 class="mb-2 text-center text-3xl font-bold text-gray-800">生命力教育联盟教育</h1>
12 <!-- <h2 class="text-center text-xl font-medium text-gray-600">欢迎回来</h2> --> 12 <!-- <h2 class="text-center text-xl font-medium text-gray-600">欢迎回来</h2> -->
13 </div> 13 </div>
14 14
...@@ -168,7 +168,7 @@ ...@@ -168,7 +168,7 @@
168 class="cursor-pointer font-medium text-green-600 hover:text-green-500" 168 class="cursor-pointer font-medium text-green-600 hover:text-green-500"
169 @click="userAgreementRef.openAgreement()" 169 @click="userAgreementRef.openAgreement()"
170 > 170 >
171 -美乐爱觉宇宙用户协议》 171 +生命力教育联盟宇宙用户协议》
172 </span> 172 </span>
173 <UserAgreement ref="userAgreementRef" /> 173 <UserAgreement ref="userAgreementRef" />
174 </p> 174 </p>
......
1 <template> 1 <template>
2 - <div class="min-h-screen flex flex-col bg-gradient-to-br from-green-50 via-teal-50 to-blue-50 py-12 px-4 sm:px-6 lg:px-8"> 2 + <div
3 + class="flex min-h-screen flex-col bg-gradient-to-br from-green-50 via-teal-50 to-blue-50 px-4 py-12 sm:px-6 lg:px-8"
4 + >
3 <div class="sm:mx-auto sm:w-full sm:max-w-md"> 5 <div class="sm:mx-auto sm:w-full sm:max-w-md">
4 - <h1 class="text-center text-3xl font-bold text-gray-800 mb-2">美乐爱觉教育</h1> 6 + <h1 class="mb-2 text-center text-3xl font-bold text-gray-800">生命力教育联盟教育</h1>
5 <h2 class="text-center text-xl font-medium text-gray-600">创建账号</h2> 7 <h2 class="text-center text-xl font-medium text-gray-600">创建账号</h2>
6 </div> 8 </div>
7 9
8 <div class="mt-8 sm:mx-auto sm:w-full sm:max-w-md"> 10 <div class="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
9 - <FrostedGlass class="py-8 px-6 rounded-lg"> 11 + <FrostedGlass class="rounded-lg px-6 py-8">
10 - <div v-if="error" class="mb-4 bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded-md"> 12 + <div
13 + v-if="error"
14 + class="mb-4 rounded-md border border-red-400 bg-red-100 px-4 py-3 text-red-700"
15 + >
11 {{ error }} 16 {{ error }}
12 </div> 17 </div>
13 18
...@@ -21,7 +26,7 @@ ...@@ -21,7 +26,7 @@
21 v-model="formData.name" 26 v-model="formData.name"
22 type="text" 27 type="text"
23 required 28 required
24 - class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-green-500 focus:border-green-500" 29 + class="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-green-500 focus:outline-none focus:ring-green-500"
25 /> 30 />
26 </div> 31 </div>
27 32
...@@ -39,7 +44,7 @@ ...@@ -39,7 +44,7 @@
39 maxlength="11" 44 maxlength="11"
40 @input="formData.phone = formData.phone.replace(/\D/g, '')" 45 @input="formData.phone = formData.phone.replace(/\D/g, '')"
41 @blur="validatePhone" 46 @blur="validatePhone"
42 - class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-green-500 focus:border-green-500" 47 + class="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-green-500 focus:outline-none focus:ring-green-500"
43 /> 48 />
44 </div> 49 </div>
45 50
...@@ -54,13 +59,13 @@ ...@@ -54,13 +59,13 @@
54 type="text" 59 type="text"
55 required 60 required
56 maxlength="6" 61 maxlength="6"
57 - class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-green-500 focus:border-green-500" 62 + class="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-green-500 focus:outline-none focus:ring-green-500"
58 /> 63 />
59 <button 64 <button
60 type="button" 65 type="button"
61 :disabled="countdown > 0 || !isPhoneValid" 66 :disabled="countdown > 0 || !isPhoneValid"
62 @click="sendVerificationCode" 67 @click="sendVerificationCode"
63 - class="mt-1 px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-green-600 hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500 disabled:opacity-50 disabled:cursor-not-allowed whitespace-nowrap" 68 + class="mt-1 whitespace-nowrap rounded-md border border-transparent bg-green-600 px-4 py-2 text-sm font-medium text-white hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
64 > 69 >
65 {{ countdown > 0 ? `${countdown}秒后重试` : '获取验证码' }} 70 {{ countdown > 0 ? `${countdown}秒后重试` : '获取验证码' }}
66 </button> 71 </button>
...@@ -78,7 +83,7 @@ ...@@ -78,7 +83,7 @@
78 autocomplete="new-password" 83 autocomplete="new-password"
79 required 84 required
80 minlength="6" 85 minlength="6"
81 - class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-green-500 focus:border-green-500" 86 + class="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-green-500 focus:outline-none focus:ring-green-500"
82 /> 87 />
83 </div> 88 </div>
84 89
...@@ -93,7 +98,7 @@ ...@@ -93,7 +98,7 @@
93 autocomplete="new-password" 98 autocomplete="new-password"
94 required 99 required
95 minlength="6" 100 minlength="6"
96 - class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-green-500 focus:border-green-500" 101 + class="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-green-500 focus:outline-none focus:ring-green-500"
97 /> 102 />
98 </div> 103 </div>
99 104
...@@ -105,15 +110,25 @@ ...@@ -105,15 +110,25 @@
105 checked-color="#4caf50" 110 checked-color="#4caf50"
106 class="scale-90" 111 class="scale-90"
107 icon-size="18px" 112 icon-size="18px"
108 - ><span class="text-sm">我已阅读并同意 <a href="#" class="text-green-600 hover:text-green-500" @click.prevent="openTerms">用户协议</a> 和 <a href="#" class="text-green-600 hover:text-green-500" @click.prevent="openPrivacy">隐私政策</a></span></van-checkbox> 113 + ><span class="text-sm"
114 + >我已阅读并同意
115 + <a href="#" class="text-green-600 hover:text-green-500" @click.prevent="openTerms"
116 + >用户协议</a
117 + >
118 +
119 + <a href="#" class="text-green-600 hover:text-green-500" @click.prevent="openPrivacy"
120 + >隐私政策</a
121 + ></span
122 + ></van-checkbox
123 + >
109 </div> 124 </div>
110 125
111 <div> 126 <div>
112 <button 127 <button
113 type="submit" 128 type="submit"
114 :disabled="loading" 129 :disabled="loading"
115 - class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-gradient-to-r from-green-500 to-green-600 hover:from-green-600 hover:to-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500" 130 + class="flex w-full justify-center rounded-md border border-transparent bg-gradient-to-r from-green-500 to-green-600 px-4 py-2 text-sm font-medium text-white shadow-sm hover:from-green-600 hover:to-green-700 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2"
116 - :class="{ 'opacity-70 cursor-not-allowed': loading }" 131 + :class="{ 'cursor-not-allowed opacity-70': loading }"
117 > 132 >
118 {{ loading ? '注册中...' : '立即注册' }} 133 {{ loading ? '注册中...' : '立即注册' }}
119 </button> 134 </button>
...@@ -154,7 +169,7 @@ ...@@ -154,7 +169,7 @@
154 </div> 169 </div>
155 </div> --> 170 </div> -->
156 171
157 - <div class="text-center mt-6"> 172 + <div class="mt-6 text-center">
158 <p class="text-sm text-gray-600"> 173 <p class="text-sm text-gray-600">
159 已有账号? 174 已有账号?
160 <router-link to="/login" class="font-medium text-green-600 hover:text-green-500"> 175 <router-link to="/login" class="font-medium text-green-600 hover:text-green-500">
...@@ -165,16 +180,8 @@ ...@@ -165,16 +180,8 @@
165 </FrostedGlass> 180 </FrostedGlass>
166 </div> 181 </div>
167 182
168 - <TermsPopup 183 + <TermsPopup v-model:show="showTerms" :type="popupType" :title="popupTitle" />
169 - v-model:show="showTerms" 184 + <TermsPopup v-model:show="showPrivacy" :type="popupType" :title="popupTitle" />
170 - :type="popupType"
171 - :title="popupTitle"
172 - />
173 - <TermsPopup
174 - v-model:show="showPrivacy"
175 - :type="popupType"
176 - :title="popupTitle"
177 - />
178 </div> 185 </div>
179 </template> 186 </template>
180 187
...@@ -184,13 +191,13 @@ import { useRoute, useRouter } from 'vue-router' ...@@ -184,13 +191,13 @@ import { useRoute, useRouter } from 'vue-router'
184 import FrostedGlass from '@/components/effects/FrostedGlass.vue' 191 import FrostedGlass from '@/components/effects/FrostedGlass.vue'
185 import TermsPopup from '@/components/common/TermsPopup.vue' 192 import TermsPopup from '@/components/common/TermsPopup.vue'
186 import { useAuth } from '@/contexts/auth' 193 import { useAuth } from '@/contexts/auth'
187 -import { useTitle } from '@vueuse/core'; 194 +import { useTitle } from '@vueuse/core'
188 -import { smsAPI } from '@/api/common'; 195 +import { smsAPI } from '@/api/common'
189 -import { registerAPI } from '@/api/users'; 196 +import { registerAPI } from '@/api/users'
190 -import { showToast } from 'vant'; 197 +import { showToast } from 'vant'
191 198
192 -const $route = useRoute(); 199 +const $route = useRoute()
193 -useTitle($route.meta.title); 200 +useTitle($route.meta.title)
194 201
195 const router = useRouter() 202 const router = useRouter()
196 const { login } = useAuth() 203 const { login } = useAuth()
...@@ -203,7 +210,7 @@ const formData = reactive({ ...@@ -203,7 +210,7 @@ const formData = reactive({
203 verificationCode: '', 210 verificationCode: '',
204 password: '', 211 password: '',
205 confirmPassword: '', 212 confirmPassword: '',
206 - agreeTerms: false 213 + agreeTerms: false,
207 }) 214 })
208 215
209 const startCountdown = () => { 216 const startCountdown = () => {
...@@ -293,7 +300,7 @@ const handleSubmit = async () => { ...@@ -293,7 +300,7 @@ const handleSubmit = async () => {
293 const success = login({ 300 const success = login({
294 name: formData.name, 301 name: formData.name,
295 mobile: formData.phone, 302 mobile: formData.phone,
296 - avatar: '' 303 + avatar: '',
297 }) 304 })
298 if (success) { 305 if (success) {
299 router.push('/') 306 router.push('/')
......
1 <template> 1 <template>
2 <AppLayout :right-content="rightContent"> 2 <AppLayout :right-content="rightContent">
3 - <div 3 + <div class="min-h-screen bg-gradient-to-br from-green-50 via-green-100/30 to-blue-50/30">
4 - class="bg-gradient-to-br from-green-50 via-green-100/30 to-blue-50/30 min-h-screen"
5 - >
6 <!-- User Profile Header with Enhanced Design --> 4 <!-- User Profile Header with Enhanced Design -->
7 - <div class="pt-6 pb-8 relative"> 5 + <div class="relative pb-8 pt-6">
8 - <div 6 + <div class="absolute inset-0 bg-gradient-to-r from-green-500 to-blue-500 opacity-15"></div>
9 - class="absolute inset-0 bg-gradient-to-r from-green-500 to-blue-500 opacity-15"
10 - ></div>
11 <div class="relative z-10 flex flex-col items-center"> 7 <div class="relative z-10 flex flex-col items-center">
12 - <div 8 + <div class="mb-4 h-24 w-24 overflow-hidden rounded-full border-4 border-white shadow-lg">
13 - class="w-24 h-24 rounded-full overflow-hidden border-4 border-white shadow-lg mb-4"
14 - >
15 <img 9 <img
16 :src="profile.avatar || 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg'" 10 :src="profile.avatar || 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg'"
17 :alt="profile.name" 11 :alt="profile.name"
18 - class="w-full h-full object-cover" 12 + class="h-full w-full object-cover"
19 @error="handleImageError" 13 @error="handleImageError"
20 /> 14 />
21 </div> 15 </div>
22 - <h2 class="text-2xl font-bold mb-1">{{ profile.name || '匿名用户' }}</h2> 16 + <h2 class="mb-1 text-2xl font-bold">{{ profile.name || '匿名用户' }}</h2>
23 <!-- <div class="flex items-center text-sm text-gray-600"> 17 <!-- <div class="flex items-center text-sm text-gray-600">
24 <span>会员等级: 普通会员</span> 18 <span>会员等级: 普通会员</span>
25 <span class="mx-2">|</span> 19 <span class="mx-2">|</span>
...@@ -29,40 +23,46 @@ ...@@ -29,40 +23,46 @@
29 </div> 23 </div>
30 24
31 <!-- Check-in Statistics --> 25 <!-- Check-in Statistics -->
32 - <div class="px-4 mb-5 pt-4"> 26 + <div class="mb-5 px-4 pt-4">
33 - <FrostedGlass class="p-4 rounded-xl"> 27 + <FrostedGlass class="rounded-xl p-4">
34 - <div class="flex justify-between items-center mb-4"> 28 + <div class="mb-4 flex items-center justify-between">
35 - <h3 class="font-semibold text-base">打卡统计</h3> 29 + <h3 class="text-base font-semibold">打卡统计</h3>
36 <!-- <span class="text-xs text-blue-500">查看更多</span> --> 30 <!-- <span class="text-xs text-blue-500">查看更多</span> -->
37 </div> 31 </div>
38 32
39 - <div class="grid items-center gap-2" style="grid-template-columns: 1fr 1fr 1fr auto;"> 33 + <div class="grid items-center gap-2" style="grid-template-columns: 1fr 1fr 1fr auto">
40 - <div class="flex flex-col items-center min-w-0"> 34 + <div class="flex min-w-0 flex-col items-center">
41 - <div class="font-bold text-gray-800 text-xl text-center w-full truncate px-0.5 flex items-baseline justify-center"> 35 + <div
36 + class="flex w-full items-baseline justify-center truncate px-0.5 text-center text-xl font-bold text-gray-800"
37 + >
42 <span>{{ formatCheckInCount(checkIns?.total_days) }}</span> 38 <span>{{ formatCheckInCount(checkIns?.total_days) }}</span>
43 - <span class="text-xs ml-1 font-normal">天</span> 39 + <span class="ml-1 text-xs font-normal">天</span>
44 </div> 40 </div>
45 - <div class="text-xs text-gray-500 mt-1 truncate w-full text-center">累计打卡</div> 41 + <div class="mt-1 w-full truncate text-center text-xs text-gray-500">累计打卡</div>
46 </div> 42 </div>
47 - <div class="flex flex-col items-center min-w-0"> 43 + <div class="flex min-w-0 flex-col items-center">
48 - <div class="font-bold text-green-600 text-xl text-center w-full truncate px-0.5 flex items-baseline justify-center"> 44 + <div
45 + class="flex w-full items-baseline justify-center truncate px-0.5 text-center text-xl font-bold text-green-600"
46 + >
49 <span>{{ formatCheckInCount(checkIns?.consecutive_days) }}</span> 47 <span>{{ formatCheckInCount(checkIns?.consecutive_days) }}</span>
50 - <span class="text-xs ml-1 font-normal">天</span> 48 + <span class="ml-1 text-xs font-normal">天</span>
51 </div> 49 </div>
52 - <div class="text-xs text-gray-500 mt-1 truncate w-full text-center">连续打卡</div> 50 + <div class="mt-1 w-full truncate text-center text-xs text-gray-500">连续打卡</div>
53 </div> 51 </div>
54 - <div class="flex flex-col items-center min-w-0"> 52 + <div class="flex min-w-0 flex-col items-center">
55 - <div class="font-bold text-blue-600 text-xl text-center w-full truncate px-0.5 flex items-baseline justify-center"> 53 + <div
54 + class="flex w-full items-baseline justify-center truncate px-0.5 text-center text-xl font-bold text-blue-600"
55 + >
56 <span>{{ formatCheckInCount(checkIns?.longest_consecutive_days) }}</span> 56 <span>{{ formatCheckInCount(checkIns?.longest_consecutive_days) }}</span>
57 - <span class="text-xs ml-1 font-normal">天</span> 57 + <span class="ml-1 text-xs font-normal">天</span>
58 </div> 58 </div>
59 - <div class="text-xs text-gray-500 mt-1 truncate w-full text-center">最长连续</div> 59 + <div class="mt-1 w-full truncate text-center text-xs text-gray-500">最长连续</div>
60 </div> 60 </div>
61 61
62 <div> 62 <div>
63 <div @click="handleCheckin" class="cursor-pointer"> 63 <div @click="handleCheckin" class="cursor-pointer">
64 <button 64 <button
65 - class="bg-gradient-to-r from-green-500 to-green-600 text-white py-2 px-3 rounded-full text-sm shadow-sm whitespace-nowrap" 65 + class="whitespace-nowrap rounded-full bg-gradient-to-r from-green-500 to-green-600 px-3 py-2 text-sm text-white shadow-sm"
66 > 66 >
67 立即打卡 67 立即打卡
68 </button> 68 </button>
...@@ -74,7 +74,7 @@ ...@@ -74,7 +74,7 @@
74 74
75 <!-- User Menu Options --> 75 <!-- User Menu Options -->
76 <div class="px-4 pb-16"> 76 <div class="px-4 pb-16">
77 - <FrostedGlass class="rounded-xl overflow-hidden mb-5"> 77 + <FrostedGlass class="mb-5 overflow-hidden rounded-xl">
78 <MenuItem 78 <MenuItem
79 v-for="item in menuItems1" 79 v-for="item in menuItems1"
80 :key="item.path" 80 :key="item.path"
...@@ -83,7 +83,7 @@ ...@@ -83,7 +83,7 @@
83 /> 83 />
84 </FrostedGlass> 84 </FrostedGlass>
85 85
86 - <FrostedGlass class="rounded-xl overflow-hidden mb-5"> 86 + <FrostedGlass class="mb-5 overflow-hidden rounded-xl">
87 <MenuItem 87 <MenuItem
88 v-for="item in menuItems2" 88 v-for="item in menuItems2"
89 :key="item.path" 89 :key="item.path"
...@@ -92,7 +92,7 @@ ...@@ -92,7 +92,7 @@
92 /> 92 />
93 </FrostedGlass> 93 </FrostedGlass>
94 94
95 - <FrostedGlass v-if="isTeacher" class="rounded-xl overflow-hidden mb-5"> 95 + <FrostedGlass v-if="isTeacher" class="mb-5 overflow-hidden rounded-xl">
96 <MenuItem 96 <MenuItem
97 v-for="item in menuItems4" 97 v-for="item in menuItems4"
98 :key="item.path" 98 :key="item.path"
...@@ -101,7 +101,7 @@ ...@@ -101,7 +101,7 @@
101 /> 101 />
102 </FrostedGlass> 102 </FrostedGlass>
103 103
104 - <FrostedGlass class="rounded-xl overflow-hidden mb-5"> 104 + <FrostedGlass class="mb-5 overflow-hidden rounded-xl">
105 <MenuItem 105 <MenuItem
106 v-for="item in menuItems3" 106 v-for="item in menuItems3"
107 :key="item.path" 107 :key="item.path"
...@@ -111,7 +111,7 @@ ...@@ -111,7 +111,7 @@
111 </FrostedGlass> 111 </FrostedGlass>
112 112
113 <!-- Version Info --> 113 <!-- Version Info -->
114 - <div class="text-center text-xs text-gray-400 mb-4">美乐爱觉教育</div> 114 + <div class="mb-4 text-center text-xs text-gray-400">生命力教育联盟教育</div>
115 115
116 <!-- Logout Button --> 116 <!-- Logout Button -->
117 <!-- <button 117 <!-- <button
...@@ -132,22 +132,22 @@ ...@@ -132,22 +132,22 @@
132 </template> 132 </template>
133 133
134 <script setup> 134 <script setup>
135 -import { ref, h } from "vue"; 135 +import { ref, h } from 'vue'
136 -import { useRoute, useRouter } from "vue-router"; 136 +import { useRoute, useRouter } from 'vue-router'
137 -import AppLayout from "@/components/layout/AppLayout.vue"; 137 +import AppLayout from '@/components/layout/AppLayout.vue'
138 -import FrostedGlass from "@/components/effects/FrostedGlass.vue"; 138 +import FrostedGlass from '@/components/effects/FrostedGlass.vue'
139 -import MenuItem from "@/components/common/MenuItem.vue"; 139 +import MenuItem from '@/components/common/MenuItem.vue'
140 -import { useAuth } from "@/contexts/auth"; 140 +import { useAuth } from '@/contexts/auth'
141 -import CheckInDialog from "@/components/checkin/CheckInDialog.vue"; 141 +import CheckInDialog from '@/components/checkin/CheckInDialog.vue'
142 -import { getUserInfoAPI } from "@/api/users"; 142 +import { getUserInfoAPI } from '@/api/users'
143 -import { showToast } from "vant"; 143 +import { showToast } from 'vant'
144 -import { useTitle } from "@vueuse/core"; 144 +import { useTitle } from '@vueuse/core'
145 -import { useImageLoader } from "@/composables/useImageLoader"; 145 +import { useImageLoader } from '@/composables/useImageLoader'
146 -import { useUserInfo } from "@/composables/useUserInfo"; 146 +import { useUserInfo } from '@/composables/useUserInfo'
147 147
148 -const router = useRouter(); 148 +const router = useRouter()
149 -const $route = useRoute(); 149 +const $route = useRoute()
150 -useTitle($route.meta.title); 150 +useTitle($route.meta.title)
151 151
152 // 图片加载错误处理 152 // 图片加载错误处理
153 const { handleImageError } = useImageLoader() 153 const { handleImageError } = useImageLoader()
...@@ -155,146 +155,145 @@ const { handleImageError } = useImageLoader() ...@@ -155,146 +155,145 @@ const { handleImageError } = useImageLoader()
155 // 用户信息获取 155 // 用户信息获取
156 const { userInfo, refreshUserInfo } = useUserInfo() 156 const { userInfo, refreshUserInfo } = useUserInfo()
157 157
158 -const profile = ref({}); 158 +const profile = ref({})
159 -const checkIns = ref({}); 159 +const checkIns = ref({})
160 -const isTeacher = ref(false); 160 +const isTeacher = ref(false)
161 161
162 -const formatCheckInCount = (count) => { 162 +const formatCheckInCount = count => {
163 - const num = Number(count) || 0; 163 + const num = Number(count) || 0
164 - return num > 99 ? '99+' : num; 164 + return num > 99 ? '99+' : num
165 -}; 165 +}
166 166
167 onMounted(async () => { 167 onMounted(async () => {
168 - const userData = await refreshUserInfo(); 168 + const userData = await refreshUserInfo()
169 if (userData) { 169 if (userData) {
170 - profile.value = userData; 170 + profile.value = userData
171 checkIns.value = { 171 checkIns.value = {
172 total_days: userData.total_days || 0, 172 total_days: userData.total_days || 0,
173 consecutive_days: userData.consecutive_days || 0, 173 consecutive_days: userData.consecutive_days || 0,
174 - longest_consecutive_days: userData.longest_consecutive_days || 0 174 + longest_consecutive_days: userData.longest_consecutive_days || 0,
175 - }; 175 + }
176 - isTeacher.value = userData.is_teacher; 176 + isTeacher.value = userData.is_teacher
177 // 处理消息中心的未读消息数量 177 // 处理消息中心的未读消息数量
178 menuItems2.value.forEach(item => { 178 menuItems2.value.forEach(item => {
179 if (item.path === '/profile/messages') { 179 if (item.path === '/profile/messages') {
180 - item.badge = +(userData?.unread_msg_count || 0); 180 + item.badge = +(userData?.unread_msg_count || 0)
181 } 181 }
182 - }); 182 + })
183 } 183 }
184 }) 184 })
185 185
186 -const showCheckInDialog = ref(false); 186 +const showCheckInDialog = ref(false)
187 187
188 // 处理打卡成功 188 // 处理打卡成功
189 const handleCheckInSuccess = () => { 189 const handleCheckInSuccess = () => {
190 - checkIns.value.total_days++; 190 + checkIns.value.total_days++
191 - checkIns.value.consecutive_days++; 191 + checkIns.value.consecutive_days++
192 checkIns.value.longest_consecutive_days = Math.max( 192 checkIns.value.longest_consecutive_days = Math.max(
193 checkIns.value.longest_consecutive_days, 193 checkIns.value.longest_consecutive_days,
194 checkIns.value.consecutive_days 194 checkIns.value.consecutive_days
195 - ); 195 + )
196 -}; 196 +}
197 197
198 -const checkinData = ref([]); 198 +const checkinData = ref([])
199 -const handleCheckInData = (data) => { 199 +const handleCheckInData = data => {
200 - checkinData.value = data; 200 + checkinData.value = data
201 } 201 }
202 202
203 // Handle logout 203 // Handle logout
204 -const { logout } = useAuth(); 204 +const { logout } = useAuth()
205 const handleLogout = () => { 205 const handleLogout = () => {
206 - logout(); 206 + logout()
207 // window.location.href = import.meta.env.VITE_BASE || '/'; 207 // window.location.href = import.meta.env.VITE_BASE || '/';
208 // 返回首页 208 // 返回首页
209 - router.replace({ path: '/' }); 209 + router.replace({ path: '/' })
210 -}; 210 +}
211 211
212 // Handle menu item click 212 // Handle menu item click
213 -const handleMenuClick = (path) => { 213 +const handleMenuClick = path => {
214 if (path === '/profile/community') { 214 if (path === '/profile/community') {
215 // window.location.href = 'https://community.mlaj.com'; 215 // window.location.href = 'https://community.mlaj.com';
216 showToast('功能暂未开放') 216 showToast('功能暂未开放')
217 - } else if(path === '/profile/activities') { 217 + } else if (path === '/profile/activities') {
218 // showToast('功能暂未开放') 218 // showToast('功能暂未开放')
219 - window.location.href = 'https://wxm.behalo.cc/pages/tabBar/mine/application?type=2'; 219 + window.location.href = 'https://wxm.behalo.cc/pages/tabBar/mine/application?type=2'
220 - } else if(path === '/profile/userinfo') { 220 + } else if (path === '/profile/userinfo') {
221 // showToast('功能暂未开放') 221 // showToast('功能暂未开放')
222 - window.location.href = 'https://wxm.behalo.cc/pages/student/student?token=&user_id='; 222 + window.location.href = 'https://wxm.behalo.cc/pages/student/student?token=&user_id='
223 } else { 223 } else {
224 - router.push(path); 224 + router.push(path)
225 } 225 }
226 -}; 226 +}
227 227
228 // Handle check-in type click 228 // Handle check-in type click
229 -const handleCheckInClick = (path) => { 229 +const handleCheckInClick = path => {
230 - router.push(path); 230 + router.push(path)
231 -}; 231 +}
232 232
233 // Right content component 233 // Right content component
234 -const rightContent = h("div", { class: "flex items-center" }, [ 234 +const rightContent = h('div', { class: 'flex items-center' }, [
235 - h("button", { class: "p-2" }, [ 235 + h('button', { class: 'p-2' }, [
236 h( 236 h(
237 - "svg", 237 + 'svg',
238 { 238 {
239 - xmlns: "http://www.w3.org/2000/svg", 239 + xmlns: 'http://www.w3.org/2000/svg',
240 - class: "h-6 w-6 text-gray-700", 240 + class: 'h-6 w-6 text-gray-700',
241 - fill: "none", 241 + fill: 'none',
242 - viewBox: "0 0 24 24", 242 + viewBox: '0 0 24 24',
243 - stroke: "currentColor", 243 + stroke: 'currentColor',
244 }, 244 },
245 [ 245 [
246 - h("path", { 246 + h('path', {
247 - "stroke-linecap": "round", 247 + 'stroke-linecap': 'round',
248 - "stroke-linejoin": "round", 248 + 'stroke-linejoin': 'round',
249 - "stroke-width": "2", 249 + 'stroke-width': '2',
250 - d: 250 + d: 'M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9',
251 - "M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9",
252 }), 251 }),
253 ] 252 ]
254 ), 253 ),
255 ]), 254 ]),
256 -]); 255 +])
257 256
258 // Menu items 257 // Menu items
259 const menuItems1 = [ 258 const menuItems1 = [
260 { 259 {
261 - icon: "clock", 260 + icon: 'clock',
262 - title: "学习记录", 261 + title: '学习记录',
263 - path: "/profile/learning-records", 262 + path: '/profile/learning-records',
264 - badge: "", 263 + badge: '',
265 }, 264 },
266 { 265 {
267 - icon: "wallet", 266 + icon: 'wallet',
268 - title: "活动报名", 267 + title: '活动报名',
269 - path: "/profile/activities", 268 + path: '/profile/activities',
270 }, 269 },
271 { 270 {
272 - icon: "user", 271 + icon: 'user',
273 - title: "人员信息", 272 + title: '人员信息',
274 - path: "/profile/userinfo", 273 + path: '/profile/userinfo',
275 }, 274 },
276 { 275 {
277 - icon: "book", 276 + icon: 'book',
278 - title: "我的课程", 277 + title: '我的课程',
279 - path: "/profile/courses", 278 + path: '/profile/courses',
280 }, 279 },
281 { 280 {
282 - icon: "document", 281 + icon: 'document',
283 - title: "课程订单", 282 + title: '课程订单',
284 - path: "/profile/orders", 283 + path: '/profile/orders',
285 }, 284 },
286 -]; 285 +]
287 286
288 const menuItems2 = ref([ 287 const menuItems2 = ref([
289 { 288 {
290 - icon: "wallet", 289 + icon: 'wallet',
291 - title: "我的积分", 290 + title: '我的积分',
292 - path: "/profile/points", 291 + path: '/profile/points',
293 }, 292 },
294 { 293 {
295 - icon: "heart", 294 + icon: 'heart',
296 - title: "我的收藏", 295 + title: '我的收藏',
297 - path: "/profile/favorites", 296 + path: '/profile/favorites',
298 }, 297 },
299 // { 298 // {
300 // icon: "chat", 299 // icon: "chat",
...@@ -302,47 +301,47 @@ const menuItems2 = ref([ ...@@ -302,47 +301,47 @@ const menuItems2 = ref([
302 // path: "/profile/community", 301 // path: "/profile/community",
303 // }, 302 // },
304 { 303 {
305 - icon: "email", 304 + icon: 'email',
306 - title: "我的消息", 305 + title: '我的消息',
307 - path: "/profile/messages", 306 + path: '/profile/messages',
308 - badge: "", 307 + badge: '',
309 }, 308 },
310 -]); 309 +])
311 310
312 const menuItems3 = ref([ 311 const menuItems3 = ref([
313 { 312 {
314 - icon: "question", 313 + icon: 'question',
315 - title: "帮助中心", 314 + title: '帮助中心',
316 - path: "/profile/help", 315 + path: '/profile/help',
317 }, 316 },
318 { 317 {
319 - icon: "settings", 318 + icon: 'settings',
320 - title: "设置", 319 + title: '设置',
321 - path: "/profile/settings", 320 + path: '/profile/settings',
322 }, 321 },
323 -]); 322 +])
324 323
325 const menuItems4 = ref([ 324 const menuItems4 = ref([
326 { 325 {
327 - icon: "document", 326 + icon: 'document',
328 - title: "打卡管理", 327 + title: '打卡管理',
329 - path: "/teacher/checkin", 328 + path: '/teacher/checkin',
330 }, 329 },
331 { 330 {
332 - icon: "user", 331 + icon: 'user',
333 - title: "我的班级", 332 + title: '我的班级',
334 - path: "/teacher/myClass", 333 + path: '/teacher/myClass',
335 }, 334 },
336 { 335 {
337 - icon: "book", 336 + icon: 'book',
338 - title: "作业管理", 337 + title: '作业管理',
339 - path: "/teacher/tasks", 338 + path: '/teacher/tasks',
340 }, 339 },
341 -]); 340 +])
342 341
343 const handleCheckin = () => { 342 const handleCheckin = () => {
344 if (checkinData.value.length) { 343 if (checkinData.value.length) {
345 - showCheckInDialog.value = true; 344 + showCheckInDialog.value = true
346 } else { 345 } else {
347 showToast('暂无打卡任务') 346 showToast('暂无打卡任务')
348 } 347 }
......
1 <template> 1 <template>
2 - <div class="recall-login w-full min-h-screen relative overflow-hidden flex flex-col items-center"> 2 + <div class="recall-login relative flex min-h-screen w-full flex-col items-center overflow-hidden">
3 <!-- <VideoBackground /> --> 3 <!-- <VideoBackground /> -->
4 <StarryBackground /> 4 <StarryBackground />
5 5
6 <!-- 标题区域 --> 6 <!-- 标题区域 -->
7 - <div class="mt-10 flex flex-col items-center z-10 w-full px-8"> 7 + <div class="z-10 mt-10 flex w-full flex-col items-center px-8">
8 - <img :src="titleImg" class="w-full max-w-[300px] mb-4 object-contain" alt="title" /> 8 + <img :src="titleImg" class="mb-4 w-full max-w-[300px] object-contain" alt="title" />
9 9
10 - <div class="text-white text-center space-y-1 tracking-wider text-shadow-md"> 10 + <div class="text-shadow-md space-y-1 text-center tracking-wider text-white">
11 <p class="text-sm">请验证身份</p> 11 <p class="text-sm">请验证身份</p>
12 <p class="text-sm">开启专属您的「时光机」</p> 12 <p class="text-sm">开启专属您的「时光机」</p>
13 <p class="text-sm">见证每一段成长故事</p> 13 <p class="text-sm">见证每一段成长故事</p>
...@@ -15,66 +15,105 @@ ...@@ -15,66 +15,105 @@
15 </div> 15 </div>
16 16
17 <!-- Login Form Module --> 17 <!-- Login Form Module -->
18 - <div class="w-full px-6 mt-6 z-10"> 18 + <div class="z-10 mt-6 w-full px-6">
19 <!-- Using existing FrostedGlass component for semi-transparent effect --> 19 <!-- Using existing FrostedGlass component for semi-transparent effect -->
20 - <FrostedGlass class="p-6 !rounded-2xl !border-white/20 !shadow-none" :bg-opacity="10" blur-level="md"> 20 + <FrostedGlass
21 - <h2 class="text-white text-center text-xl font-bold mb-8 tracking-widest drop-shadow-md">手机号验证</h2> 21 + class="!rounded-2xl !border-white/20 p-6 !shadow-none"
22 + :bg-opacity="10"
23 + blur-level="md"
24 + >
25 + <h2 class="mb-8 text-center text-xl font-bold tracking-widest text-white drop-shadow-md">
26 + 手机号验证
27 + </h2>
22 28
23 <div class="space-y-5"> 29 <div class="space-y-5">
24 <!-- Phone Input --> 30 <!-- Phone Input -->
25 - <van-field v-model="phone" placeholder="请输入手机号" class="custom-input rounded-lg !bg-white/10 !text-white !border-[1px] !border-solid !border-[rgba(255,255,255,0.57)]" 31 + <van-field
26 - :border="false" type="tel" maxlength="11" /> 32 + v-model="phone"
33 + placeholder="请输入手机号"
34 + class="custom-input rounded-lg !border-[1px] !border-solid !border-[rgba(255,255,255,0.57)] !bg-white/10 !text-white"
35 + :border="false"
36 + type="tel"
37 + maxlength="11"
38 + />
27 39
28 <!-- Verification Code Input --> 40 <!-- Verification Code Input -->
29 <div class="flex gap-3"> 41 <div class="flex gap-3">
30 - <van-field v-model="code" placeholder="请输入验证码" 42 + <van-field
31 - class="custom-input rounded-lg !bg-white/10 !text-white flex-1 !border-[1px] !border-solid !border-[rgba(255,255,255,0.57)]" :border="false" type="digit" 43 + v-model="code"
32 - maxlength="6" /> 44 + placeholder="请输入验证码"
33 - <van-button plain 45 + class="custom-input flex-1 rounded-lg !border-[1px] !border-solid !border-[rgba(255,255,255,0.57)] !bg-white/10 !text-white"
34 - class="verify-btn !bg-transparent !text-white !border-[#FFDD01] !rounded-lg !px-4 !h-[44px] !font-normal" 46 + :border="false"
35 - @click="handleSendCode" :disabled="counting"> 47 + type="digit"
48 + maxlength="6"
49 + />
50 + <van-button
51 + plain
52 + class="verify-btn !h-[44px] !rounded-lg !border-[#FFDD01] !bg-transparent !px-4 !font-normal !text-white"
53 + @click="handleSendCode"
54 + :disabled="counting"
55 + >
36 {{ counting ? `${count}s` : '获取验证码' }} 56 {{ counting ? `${count}s` : '获取验证码' }}
37 </van-button> 57 </van-button>
38 </div> 58 </div>
39 59
40 <!-- Next Step Button --> 60 <!-- Next Step Button -->
41 - <van-button block 61 + <van-button
42 - class="submit-btn !mt-8 !rounded-lg !bg-transparent !border-[#FFDD01] !text-[#FFDD01] !font-bold !text-lg !h-[48px]" 62 + block
43 - @click="handleLogin"> 63 + class="submit-btn !mt-8 !h-[48px] !rounded-lg !border-[#FFDD01] !bg-transparent !text-lg !font-bold !text-[#FFDD01]"
64 + @click="handleLogin"
65 + >
44 下一步 66 下一步
45 </van-button> 67 </van-button>
46 </div> 68 </div>
47 69
48 <!-- Footer Agreement Text --> 70 <!-- Footer Agreement Text -->
49 - <div class="mt-6 text-center text-xs text-white/90 leading-relaxed"> 71 + <div class="mt-6 text-center text-xs leading-relaxed text-white/90">
50 点击“下一步”,即表示您同意我们的 72 点击“下一步”,即表示您同意我们的
51 <br /> 73 <br />
52 - <span class="text-[#FFDD01] cursor-pointer hover:opacity-80 transition-opacity" 74 + <span
53 - @click="showAgreement = true">《美乐爱觉宇宙用户协议》</span> 75 + class="cursor-pointer text-[#FFDD01] transition-opacity hover:opacity-80"
76 + @click="showAgreement = true"
77 + >《生命力教育联盟宇宙用户协议》</span
78 + >
54 </div> 79 </div>
55 </FrostedGlass> 80 </FrostedGlass>
56 </div> 81 </div>
57 82
58 <!-- Agreement Popup --> 83 <!-- Agreement Popup -->
59 - <van-popup v-model:show="showAgreement" round position="bottom" :style="{ height: '70%' }" closeable 84 + <van-popup
60 - class="agreement-popup"> 85 + v-model:show="showAgreement"
61 - <div class="flex flex-col h-full bg-white"> 86 + round
62 - <div class="p-4 text-center border-b border-gray-100 bg-white sticky top-0 z-10"> 87 + position="bottom"
63 - <h3 class="font-bold text-lg text-gray-800">美乐爱觉宇宙用户协议</h3> 88 + :style="{ height: '70%' }"
89 + closeable
90 + class="agreement-popup"
91 + >
92 + <div class="flex h-full flex-col bg-white">
93 + <div class="sticky top-0 z-10 border-b border-gray-100 bg-white p-4 text-center">
94 + <h3 class="text-lg font-bold text-gray-800">生命力教育联盟宇宙用户协议</h3>
64 </div> 95 </div>
65 - <div class="flex-1 overflow-y-auto p-5 scroll-smooth"> 96 + <div class="flex-1 overflow-y-auto scroll-smooth p-5">
66 - <div class="text-sm text-gray-600 leading-relaxed text-justify space-y-4"> 97 + <div class="space-y-4 text-justify text-sm leading-relaxed text-gray-600">
67 <div v-for="(section, index) in agreementSections" :key="index"> 98 <div v-for="(section, index) in agreementSections" :key="index">
68 - <h4 v-if="section.title" class="font-bold text-gray-800 mb-2 mt-4 text-base">{{ section.title }}</h4> 99 + <h4 v-if="section.title" class="mb-2 mt-4 text-base font-bold text-gray-800">
100 + {{ section.title }}
101 + </h4>
69 <p v-for="(para, pIndex) in section.content" :key="pIndex" class="mb-2 indent-2"> 102 <p v-for="(para, pIndex) in section.content" :key="pIndex" class="mb-2 indent-2">
70 {{ para }} 103 {{ para }}
71 </p> 104 </p>
72 </div> 105 </div>
73 </div> 106 </div>
74 </div> 107 </div>
75 - <div class="p-4 border-t border-gray-100 bg-white safe-area-bottom"> 108 + <div class="safe-area-bottom border-t border-gray-100 bg-white p-4">
76 - <van-button block round type="primary" color="linear-gradient(to right, #FFDD01, #E5C600)" 109 + <van-button
77 - class="!text-white !font-bold !h-[44px]" @click="showAgreement = false"> 110 + block
111 + round
112 + type="primary"
113 + color="linear-gradient(to right, #FFDD01, #E5C600)"
114 + class="!h-[44px] !font-bold !text-white"
115 + @click="showAgreement = false"
116 + >
78 我已阅读并同意 117 我已阅读并同意
79 </van-button> 118 </van-button>
80 </div> 119 </div>
...@@ -88,7 +127,7 @@ import { ref, computed, onMounted } from 'vue' ...@@ -88,7 +127,7 @@ import { ref, computed, onMounted } from 'vue'
88 import { useRouter, useRoute } from 'vue-router' 127 import { useRouter, useRoute } from 'vue-router'
89 import { showToast } from 'vant' 128 import { showToast } from 'vant'
90 import { useTitle } from '@vueuse/core' 129 import { useTitle } from '@vueuse/core'
91 -import { setAuthHeaders } from "@/utils/axios"; 130 +import { setAuthHeaders } from '@/utils/axios'
92 import VideoBackground from '@/components/media/VideoBackground.vue' 131 import VideoBackground from '@/components/media/VideoBackground.vue'
93 import { applyUserInfoAuth } from '@/utils/auth_user_info' 132 import { applyUserInfoAuth } from '@/utils/auth_user_info'
94 133
...@@ -173,26 +212,34 @@ const handleLogin = async () => { ...@@ -173,26 +212,34 @@ const handleLogin = async () => {
173 } 212 }
174 213
175 try { 214 try {
176 - const res = await loginAPI({ mobile: phone.value, sms_code: code.value, entry: entry.value, referrer_user_id: referrer_user_id.value }) 215 + const res = await loginAPI({
216 + mobile: phone.value,
217 + sms_code: code.value,
218 + entry: entry.value,
219 + referrer_user_id: referrer_user_id.value,
220 + })
177 if (res.code === 1) { 221 if (res.code === 1) {
178 applyUserInfoAuth(res, { set_auth_headers: setAuthHeaders, storage: localStorage }) 222 applyUserInfoAuth(res, { set_auth_headers: setAuthHeaders, storage: localStorage })
179 const userInfo = await userInfoAPI() 223 const userInfo = await userInfoAPI()
180 // 登录之后需要判断是否有完善个人信息 224 // 登录之后需要判断是否有完善个人信息
181 if (userInfo.code === 1) { 225 if (userInfo.code === 1) {
182 - const info = userInfo.data.user || ''; 226 + const info = userInfo.data.user || ''
183 - if (!info.has_idcard) { // 如果【查询我的信息】没有填写过身份证(has_idcard 为 false),则进入完善个人信息页 227 + if (!info.has_idcard) {
228 + // 如果【查询我的信息】没有填写过身份证(has_idcard 为 false),则进入完善个人信息页
184 $router.push('/recall/boot') 229 $router.push('/recall/boot')
185 - } else { // 如果【查询我的信息】填写过身份证(has_idcard 为 true) 230 + } else {
186 - if (!info.has_activity_registration) { // 如果【查询我的信息】中没有兑换过星球币(has_activity_registration 为 false),则进入二次查询历史活动页 231 + // 如果【查询我的信息】填写过身份证(has_idcard 为 true)
232 + if (!info.has_activity_registration) {
233 + // 如果【查询我的信息】中没有兑换过星球币(has_activity_registration 为 false),则进入二次查询历史活动页
187 $router.push('/recall/id-query') 234 $router.push('/recall/id-query')
188 - } else { // 如果【查询我的信息】中兑换过星球币(has_activity_registration 为 true),则进入时光机页面 235 + } else {
236 + // 如果【查询我的信息】中兑换过星球币(has_activity_registration 为 true),则进入时光机页面
189 $router.push('/recall/timeline') 237 $router.push('/recall/timeline')
190 } 238 }
191 } 239 }
192 } 240 }
193 } 241 }
194 - } 242 + } catch (error) {
195 - catch (error) {
196 console.error('登录失败:', error) 243 console.error('登录失败:', error)
197 showToast('登录失败,请稍后重试') 244 showToast('登录失败,请稍后重试')
198 } 245 }
...@@ -203,45 +250,45 @@ const agreementSections = [ ...@@ -203,45 +250,45 @@ const agreementSections = [
203 { 250 {
204 title: '一、总则', 251 title: '一、总则',
205 content: [ 252 content: [
206 - '1、“美乐爱觉”软件及相关服务,系指杭州南风教育科技有限公司(以下简称“南方教育”)合法拥有并运营的、标注名称为“美乐爱觉”的客户端、网站(https://wxm.behalo.cc)、WAP、小程序、公众号等及相关网站向您提供的产品与服务(以下统称“美乐爱觉平台”)。《“ 美乐爱觉平台”用户服务协议》(以下称“本协议”)是您与公司就您下载、安装、注册、登录、使用(以下统称“使用”)美乐爱觉互联网平台终端,并获得美乐爱觉平台提供的相关服务所订立的协议。', 253 + '1、“生命力教育联盟”软件及相关服务,系指杭州南风教育科技有限公司(以下简称“南方教育”)合法拥有并运营的、标注名称为“生命力教育联盟”的客户端、网站(https://wxm.behalo.cc)、WAP、小程序、公众号等及相关网站向您提供的产品与服务(以下统称“生命力教育联盟平台”)。《“ 生命力教育联盟平台”用户服务协议》(以下称“本协议”)是您与公司就您下载、安装、注册、登录、使用(以下统称“使用”)生命力教育联盟互联网平台终端,并获得生命力教育联盟平台提供的相关服务所订立的协议。',
207 - '2、在此特别提醒您(以下或称“用户”)在注册成为美乐爱觉平台用户之前,应当认真阅读本《用户服务协议》(以下简称“协议”),确保您充分理解本协议中各条款,并选择接受或不接受本协议。其中,对于免除或限制责任条款等内容将以加粗形式提醒您注意,您应重点阅读。除非您接受本协议所有条款,否则您无权注册、登录或使用本协议所涉服务。您的注册、登录、使用等行为即视为您已充分阅读、理解并同意完全接受本协议的全部内容,用户应当受本协议的约束。如您未满18周岁,请您应在法定监护人的陪同下仔细阅读本协议并充分理解本协议,并征得法定监护人的同意后方可注册成为美乐爱觉平台用户。', 254 + '2、在此特别提醒您(以下或称“用户”)在注册成为生命力教育联盟平台用户之前,应当认真阅读本《用户服务协议》(以下简称“协议”),确保您充分理解本协议中各条款,并选择接受或不接受本协议。其中,对于免除或限制责任条款等内容将以加粗形式提醒您注意,您应重点阅读。除非您接受本协议所有条款,否则您无权注册、登录或使用本协议所涉服务。您的注册、登录、使用等行为即视为您已充分阅读、理解并同意完全接受本协议的全部内容,用户应当受本协议的约束。如您未满18周岁,请您应在法定监护人的陪同下仔细阅读本协议并充分理解本协议,并征得法定监护人的同意后方可注册成为生命力教育联盟平台用户。',
208 - '3、本协议约定美乐爱觉平台与用户之间关于“美乐爱觉平台”服务(以下简称“服务”)的权利义务。“用户”是指注册、登录、使用本服务的个人。本协议可由美乐爱觉平台随时更新,更新后的协议条款一旦公布即代替原来的协议条款,并将以弹窗或其他形式提醒用户。用户可在本APP中查阅最新版协议条款。在修改协议条款后,如您不接受修改后的条款,您也可以选择停止使用,美乐爱觉平台亦有权因此终止您的注册进程及服务使用。您继续使用美乐爱觉平台提供的服务,则视为您已充分理解最新协议,并同意作为本协议的一方当事人接受本协议以及其他与“美乐爱觉平台”软件及相关服务相关的协议和规则(包括但不限于《“美乐爱觉平台”隐私政策》)的约束。' 255 + '3、本协议约定生命力教育联盟平台与用户之间关于“生命力教育联盟平台”服务(以下简称“服务”)的权利义务。“用户”是指注册、登录、使用本服务的个人。本协议可由生命力教育联盟平台随时更新,更新后的协议条款一旦公布即代替原来的协议条款,并将以弹窗或其他形式提醒用户。用户可在本APP中查阅最新版协议条款。在修改协议条款后,如您不接受修改后的条款,您也可以选择停止使用,生命力教育联盟平台亦有权因此终止您的注册进程及服务使用。您继续使用生命力教育联盟平台提供的服务,则视为您已充分理解最新协议,并同意作为本协议的一方当事人接受本协议以及其他与“生命力教育联盟平台”软件及相关服务相关的协议和规则(包括但不限于《“生命力教育联盟平台”隐私政策》)的约束。',
209 - ] 256 + ],
210 }, 257 },
211 { 258 {
212 title: '二、账号注册', 259 title: '二、账号注册',
213 content: [ 260 content: [
214 - '1、"美乐爱觉平台"公众号、小程序、APP、网站等基础功能使用无需注册登录,部分涉及用户数据的功能在使用前需要注册一个“美乐爱觉平台”账号,经“美乐爱觉平台”注册系统完成注册程序并通过身份认证的用户即成为正式用户,可以获得本协议规定用户应当享有的一切权限;未经身份认证用户不享有任何使用权限。', 261 + '1、"生命力教育联盟平台"公众号、小程序、APP、网站等基础功能使用无需注册登录,部分涉及用户数据的功能在使用前需要注册一个“生命力教育联盟平台”账号,经“生命力教育联盟平台”注册系统完成注册程序并通过身份认证的用户即成为正式用户,可以获得本协议规定用户应当享有的一切权限;未经身份认证用户不享有任何使用权限。',
215 - '2、“美乐爱觉平台”账号可使用手机号码或第三方平台账户(微信、QQ、Appleid)绑定注册,请用户使用尚未与“美乐爱觉平台”账号绑定的账户,以及未被美乐爱觉平台根据本协议封禁的账户注册“美乐爱觉平台”账号。美乐爱觉平台可以根据用户需求或产品需要对账号注册和绑定的方式进行变更,而无须事先通知用户。', 262 + '2、“生命力教育联盟平台”账号可使用手机号码或第三方平台账户(微信、QQ、Appleid)绑定注册,请用户使用尚未与“生命力教育联盟平台”账号绑定的账户,以及未被生命力教育联盟平台根据本协议封禁的账户注册“生命力教育联盟平台”账号。生命力教育联盟平台可以根据用户需求或产品需要对账号注册和绑定的方式进行变更,而无须事先通知用户。',
216 - '3、如果注册申请者有被美乐爱觉平台封禁的先例或涉嫌虚假注册及滥用他人名义注册,及其他不能得到许可的理由,美乐爱觉平台将拒绝其注册申请。', 263 + '3、如果注册申请者有被生命力教育联盟平台封禁的先例或涉嫌虚假注册及滥用他人名义注册,及其他不能得到许可的理由,生命力教育联盟平台将拒绝其注册申请。',
217 - '4、在用户注册及使用本服务时,美乐爱觉平台需要搜集能识别用户身份的个人信息以便美乐爱觉平台可以在必要时联系用户,或为用户提供更好的使用体验。您同意美乐爱觉平台为向您提供服务而收集您的个人信息,美乐爱觉平台搜集的信息包括但不限于用户手机号码、第三方平台账户、昵称等用户同意授权的信息。美乐爱觉平台对这些信息的使用将受限于用户个人隐私信息保护的约束。' 264 + '4、在用户注册及使用本服务时,生命力教育联盟平台需要搜集能识别用户身份的个人信息以便生命力教育联盟平台可以在必要时联系用户,或为用户提供更好的使用体验。您同意生命力教育联盟平台为向您提供服务而收集您的个人信息,生命力教育联盟平台搜集的信息包括但不限于用户手机号码、第三方平台账户、昵称等用户同意授权的信息。生命力教育联盟平台对这些信息的使用将受限于用户个人隐私信息保护的约束。',
218 - ] 265 + ],
219 }, 266 },
220 { 267 {
221 title: '三、用户使用规则', 268 title: '三、用户使用规则',
222 content: [ 269 content: [
223 - '1、您理解并承诺,您所设置的帐号不得违反国家法律法规及“美乐爱觉平台”的相关规则,您的帐号名称、头像和简介等注册信息及其他个人信息中不得出现违法和不良信息,未经他人许可不得用他人名义(包括但不限于冒用他人姓名、名称、字号、头像等或采取其他足以让人引起混淆的方式)开设帐号,不得恶意注册“美乐爱觉平台”帐号(包括但不限于频繁注册、批量注册帐号等行为)。您在帐号注册及使用过程中需遵守相关法律法规,不得实施任何侵害国家利益、损害其他公民合法权益,有害社会道德风尚的行为。公司有权对您提交的注册信息进行审核。', 270 + '1、您理解并承诺,您所设置的帐号不得违反国家法律法规及“生命力教育联盟平台”的相关规则,您的帐号名称、头像和简介等注册信息及其他个人信息中不得出现违法和不良信息,未经他人许可不得用他人名义(包括但不限于冒用他人姓名、名称、字号、头像等或采取其他足以让人引起混淆的方式)开设帐号,不得恶意注册“生命力教育联盟平台”帐号(包括但不限于频繁注册、批量注册帐号等行为)。您在帐号注册及使用过程中需遵守相关法律法规,不得实施任何侵害国家利益、损害其他公民合法权益,有害社会道德风尚的行为。公司有权对您提交的注册信息进行审核。',
224 - '2、您有责任维护个人帐号、密码的安全性与保密性,并对您以注册帐号名义所从事的活动承担全部法律责任,包括但不限于您在“美乐爱觉平台”软件及相关服务上进行的任何数据修改、言论发表、款项支付等操作行为可能引起的一切法律责任。您应高度重视对帐号与密码的保密,在任何情况下不向他人透露帐号及密码。若发现他人未经许可使用您的帐号或发生其他任何安全漏洞问题时,您应当立即通知公司。', 271 + '2、您有责任维护个人帐号、密码的安全性与保密性,并对您以注册帐号名义所从事的活动承担全部法律责任,包括但不限于您在“生命力教育联盟平台”软件及相关服务上进行的任何数据修改、言论发表、款项支付等操作行为可能引起的一切法律责任。您应高度重视对帐号与密码的保密,在任何情况下不向他人透露帐号及密码。若发现他人未经许可使用您的帐号或发生其他任何安全漏洞问题时,您应当立即通知公司。',
225 - '3、用户同意:美乐爱觉在提供服务的过程中以各种方式投放推广信息(包括但不限于:电子邮件、网站联络方式、在美乐爱觉平台的任何位置上投放),用户同意接受美乐爱觉以上述方式向用户发送推广信息。' 272 + '3、用户同意:生命力教育联盟在提供服务的过程中以各种方式投放推广信息(包括但不限于:电子邮件、网站联络方式、在生命力教育联盟平台的任何位置上投放),用户同意接受生命力教育联盟以上述方式向用户发送推广信息。',
226 - ] 273 + ],
227 }, 274 },
228 { 275 {
229 title: '四、账户安全', 276 title: '四、账户安全',
230 content: [ 277 content: [
231 - '1、用户一旦注册成功,成为美乐爱觉平台的用户,将有权利使用自己的用户名及密码随时登陆美乐爱觉平台。', 278 + '1、用户一旦注册成功,成为生命力教育联盟平台的用户,将有权利使用自己的用户名及密码随时登陆生命力教育联盟平台。',
232 '2、用户对用户名和密码的安全负责,同时对以其账户进行的所有活动和事件负全部责任。', 279 '2、用户对用户名和密码的安全负责,同时对以其账户进行的所有活动和事件负全部责任。',
233 - '3、用户不得以任何形式擅自转让或授权他人使用自己的美乐爱觉平台账户。', 280 + '3、用户不得以任何形式擅自转让或授权他人使用自己的生命力教育联盟平台账户。',
234 - '4、如果用户泄漏了账户密码,或用户发现任何人未经授权使用您的账号和密码的情况,应当立即修改密码并与美乐爱觉平台客服人员取得联系,并授权美乐爱觉平台暂停提供服务及展开调查,根据调查结果作出相应处理。用户理解美乐爱觉平台根据用户请求采取行动需要合理时间,美乐爱觉平台对采取行动前已经产生的后果和损失不承担任何责任。', 281 + '4、如果用户泄漏了账户密码,或用户发现任何人未经授权使用您的账号和密码的情况,应当立即修改密码并与生命力教育联盟平台客服人员取得联系,并授权生命力教育联盟平台暂停提供服务及展开调查,根据调查结果作出相应处理。用户理解生命力教育联盟平台根据用户请求采取行动需要合理时间,生命力教育联盟平台对采取行动前已经产生的后果和损失不承担任何责任。',
235 - '5、用户若发现任何非法使用用户账号或存在安全漏洞的情况,请立即通知美乐爱觉平台工作人员。', 282 + '5、用户若发现任何非法使用用户账号或存在安全漏洞的情况,请立即通知生命力教育联盟平台工作人员。',
236 - '6、因黑客行为或用户的保管疏忽导致账号非法使用,“美乐爱觉平台”不承担任何责任。' 283 + '6、因黑客行为或用户的保管疏忽导致账号非法使用,“生命力教育联盟平台”不承担任何责任。',
237 - ] 284 + ],
238 }, 285 },
239 { 286 {
240 title: '五、用户声明与保证', 287 title: '五、用户声明与保证',
241 content: [ 288 content: [
242 '1、用户承诺其为具有完全民事行为能力的民事主体,且具有履行本协议约定义务的能力。', 289 '1、用户承诺其为具有完全民事行为能力的民事主体,且具有履行本协议约定义务的能力。',
243 - '2、用户保证其为履行本协议而向美乐爱觉平台提供的全部资料均真实、有效。用户有义务在注册时提供自己的真实身份信息,并保证诸如手机号码、姓名等必要身份信息的有效性及安全性,保证美乐爱觉平台工作人员可以通过上述联系方式与用户取得联系。同时,用户也有义务在相关身份信息实际变更时及时更新有关注册资料。', 290 + '2、用户保证其为履行本协议而向生命力教育联盟平台提供的全部资料均真实、有效。用户有义务在注册时提供自己的真实身份信息,并保证诸如手机号码、姓名等必要身份信息的有效性及安全性,保证生命力教育联盟平台工作人员可以通过上述联系方式与用户取得联系。同时,用户也有义务在相关身份信息实际变更时及时更新有关注册资料。',
244 - '3、用户在使用美乐爱觉平台账号或本服务的过程中所制作、上载、复制、发布、传播的任何内容,不得违反国家相关法律制度,包括但不限于:', 291 + '3、用户在使用生命力教育联盟平台账号或本服务的过程中所制作、上载、复制、发布、传播的任何内容,不得违反国家相关法律制度,包括但不限于:',
245 '(1)反对宪法所确定的基本原则的;', 292 '(1)反对宪法所确定的基本原则的;',
246 '(2)危害国家安全,泄露国家秘密,颠覆国家政权,破坏国家统一的;', 293 '(2)危害国家安全,泄露国家秘密,颠覆国家政权,破坏国家统一的;',
247 '(3)损害国家荣誉和利益的;', 294 '(3)损害国家荣誉和利益的;',
...@@ -253,96 +300,94 @@ const agreementSections = [ ...@@ -253,96 +300,94 @@ const agreementSections = [
253 '(9)煽动非法集会、结社、游行、示威、聚众扰乱社会秩序的;', 300 '(9)煽动非法集会、结社、游行、示威、聚众扰乱社会秩序的;',
254 '(10)以非法民间组织名义活动的;', 301 '(10)以非法民间组织名义活动的;',
255 '(11)含有法律、行政法规禁止的其他内容的。', 302 '(11)含有法律、行政法规禁止的其他内容的。',
256 - '4、用户不得利用美乐爱觉平台账号或本服务制作、上载、复制、发布、传播任何干扰美乐爱觉平台正常运营,以及侵犯其他用户或第三方合法权益的内容,包括但不限于:', 303 + '4、用户不得利用生命力教育联盟平台账号或本服务制作、上载、复制、发布、传播任何干扰生命力教育联盟平台正常运营,以及侵犯其他用户或第三方合法权益的内容,包括但不限于:',
257 '(1)含有任何性或性暗示的;', 304 '(1)含有任何性或性暗示的;',
258 '(2)含有辱骂、恐吓、威胁内容的;', 305 '(2)含有辱骂、恐吓、威胁内容的;',
259 '(3)含有骚扰、垃圾广告、恶意信息、诱骗信息的;', 306 '(3)含有骚扰、垃圾广告、恶意信息、诱骗信息的;',
260 '(4)涉及他人隐私、个人信息或资料的;', 307 '(4)涉及他人隐私、个人信息或资料的;',
261 '(5)侵害他人名誉权、肖像权、知识产权、商业秘密等合法权利的;', 308 '(5)侵害他人名誉权、肖像权、知识产权、商业秘密等合法权利的;',
262 '(6)含有其他干扰本服务正常运营和侵犯其他用户或第三方合法权益内容的信息。', 309 '(6)含有其他干扰本服务正常运营和侵犯其他用户或第三方合法权益内容的信息。',
263 - '5、用户承若对其发表或者上传美乐爱觉平台的所有信息均享有完整的知识产权,或者已经得到相关权利人的合法授权,如用户违反本条规定造成美乐爱觉平台被第三人索赔的,用户应全额赔偿美乐爱觉平台一切损失费用(包括但不限于各种赔偿费、律师代理费、诉讼费及为此支出的其他合理费用)。', 310 + '5、用户承若对其发表或者上传生命力教育联盟平台的所有信息均享有完整的知识产权,或者已经得到相关权利人的合法授权,如用户违反本条规定造成生命力教育联盟平台被第三人索赔的,用户应全额赔偿生命力教育联盟平台一切损失费用(包括但不限于各种赔偿费、律师代理费、诉讼费及为此支出的其他合理费用)。',
264 - '6、当第三人认为用户发表或上传美乐爱觉平台的信息侵犯其权利,并根据相关法律法规向美乐爱觉平台发送权利通知书时,用户同意美乐爱觉平台可以自行判断决定删除涉嫌侵权信息,除非用户提交书面证据材料排除侵权的可能性,美乐爱觉平台不会自动回复上述删除信息。' 311 + '6、当第三人认为用户发表或上传生命力教育联盟平台的信息侵犯其权利,并根据相关法律法规向生命力教育联盟平台发送权利通知书时,用户同意生命力教育联盟平台可以自行判断决定删除涉嫌侵权信息,除非用户提交书面证据材料排除侵权的可能性,生命力教育联盟平台不会自动回复上述删除信息。',
265 - ] 312 + ],
266 }, 313 },
267 { 314 {
268 title: '六、服务内容', 315 title: '六、服务内容',
269 content: [ 316 content: [
270 - '1、美乐爱觉平台具体服务内容由美乐爱觉平台根据实际情况提供,包括但不限于:知识文章、视频课程等。具体以美乐爱觉平台实际提供的功能或服务为准。', 317 + '1、生命力教育联盟平台具体服务内容由生命力教育联盟平台根据实际情况提供,包括但不限于:知识文章、视频课程等。具体以生命力教育联盟平台实际提供的功能或服务为准。',
271 - '2、用户认可,美乐爱觉平台发给用户的所有通知、公告及其他消息都可通过用户所提供的联系方式向用户送达或通知。' 318 + '2、用户认可,生命力教育联盟平台发给用户的所有通知、公告及其他消息都可通过用户所提供的联系方式向用户送达或通知。',
272 - ] 319 + ],
273 }, 320 },
274 { 321 {
275 title: '七、付费课程相关', 322 title: '七、付费课程相关',
276 content: [ 323 content: [
277 - '美乐爱觉平台提供中华传统国学相关付费视频课程,视频课程属于虚拟计算机软件类商品。根据《消费者权益保护法》第二十五条规定,计算机软件等数字化商品不支持7天无理由退款,故当你购买付费服务成功后,不支持无条件退款。', 324 + '生命力教育联盟平台提供中华传统国学相关付费视频课程,视频课程属于虚拟计算机软件类商品。根据《消费者权益保护法》第二十五条规定,计算机软件等数字化商品不支持7天无理由退款,故当你购买付费服务成功后,不支持无条件退款。',
278 - '视频课程知识产权归本公司所有,用户付费购买的视频,用户仅享有播放权,不具备视频下载、视频剪辑等、视频传播等其他权利,若未经“杭州南风教育科技有限公司”许可,进行视频下载、视频剪辑等行为,本公司将依法追究其违法行为。' 325 + '视频课程知识产权归本公司所有,用户付费购买的视频,用户仅享有播放权,不具备视频下载、视频剪辑等、视频传播等其他权利,若未经“杭州南风教育科技有限公司”许可,进行视频下载、视频剪辑等行为,本公司将依法追究其违法行为。',
279 - ] 326 + ],
280 }, 327 },
281 { 328 {
282 title: '八、服务的暂停或终止', 329 title: '八、服务的暂停或终止',
283 content: [ 330 content: [
284 - '1、在下列情况下,美乐爱觉平台有权视具体情况自主决定暂停或终止向用户提供服务:', 331 + '1、在下列情况下,生命力教育联盟平台有权视具体情况自主决定暂停或终止向用户提供服务:',
285 - '(1)在用户违反本服务协议相关规定时,美乐爱觉平台有权视具体情况自主决定暂停或终止向该用户提供服务。', 332 + '(1)在用户违反本服务协议相关规定时,生命力教育联盟平台有权视具体情况自主决定暂停或终止向该用户提供服务。',
286 - '(2)如美乐爱觉平台通过用户提供的信息与用户联系时,发现用户在注册时绑定的联系方式已不存在或无法与用户取得联系的,美乐爱觉平台将以系统通知的方式告知用户更改,如用户在三个工作日内仍未能提供新的联系方式,美乐爱觉平台有权终止向该用户提供服务。', 333 + '(2)如生命力教育联盟平台通过用户提供的信息与用户联系时,发现用户在注册时绑定的联系方式已不存在或无法与用户取得联系的,生命力教育联盟平台将以系统通知的方式告知用户更改,如用户在三个工作日内仍未能提供新的联系方式,生命力教育联盟平台有权终止向该用户提供服务。',
287 '(3)本服务条款终止或更新时,用户明示不愿接受新的服务条款的。', 334 '(3)本服务条款终止或更新时,用户明示不愿接受新的服务条款的。',
288 - '(4)用户主动注销账户或用户向美乐爱觉平台申请注销其账户,经美乐爱觉平台审核同意的。', 335 + '(4)用户主动注销账户或用户向生命力教育联盟平台申请注销其账户,经生命力教育联盟平台审核同意的。',
289 - '(5)其他美乐爱觉平台认为需终止服务的情况。', 336 + '(5)其他生命力教育联盟平台认为需终止服务的情况。',
290 '2、用户理解并同意:', 337 '2、用户理解并同意:',
291 - '(1)服务终止后,美乐爱觉平台没有义务为用户保留原账号中或与之相关的任何信息,或转发任何未曾阅读或发送的信息给用户或第三方。', 338 + '(1)服务终止后,生命力教育联盟平台没有义务为用户保留原账号中或与之相关的任何信息,或转发任何未曾阅读或发送的信息给用户或第三方。',
292 - '(2)用户在使用本服务期间存在违法行为或违反本协议行为的,美乐爱觉平台仍可依据本协议想用户主张权利或依法依规向行政、司法等机关进行披露。', 339 + '(2)用户在使用本服务期间存在违法行为或违反本协议行为的,生命力教育联盟平台仍可依据本协议想用户主张权利或依法依规向行政、司法等机关进行披露。',
293 '(3)用户在使用本服务期间与其他第三方(如有)之间发生的关系,不因本服务或本协议的终止而终止,第三方仍有权向用户主张权利,用户应继续向第三方履行相关义务。', 340 '(3)用户在使用本服务期间与其他第三方(如有)之间发生的关系,不因本服务或本协议的终止而终止,第三方仍有权向用户主张权利,用户应继续向第三方履行相关义务。',
294 - '3、美乐爱觉平台保有删除APP内各类不符合法律政策或者不实信息内容而无须通知用户的权利。', 341 + '3、生命力教育联盟平台保有删除APP内各类不符合法律政策或者不实信息内容而无须通知用户的权利。',
295 - '4、若用户未遵守本协议规定的或其他服务条件的行为,美乐爱觉平台有权作出独立判断并采取暂停或关闭用户账号等措施,对于因此而造成用户无法正常使用账号及相关服务、无法正常获取用户账号内权益的等,美乐爱觉平台不承担任何责任。用户须对自己在网上的言论和行为承担法律责任。对于涉嫌违反法律法规、涉嫌违法犯罪的行为、美乐爱觉平台将保存有关记录,并有权依法向有关主管部门报告、配合有关主管部门调查、向公安机关报案等。' 342 + '4、若用户未遵守本协议规定的或其他服务条件的行为,生命力教育联盟平台有权作出独立判断并采取暂停或关闭用户账号等措施,对于因此而造成用户无法正常使用账号及相关服务、无法正常获取用户账号内权益的等,生命力教育联盟平台不承担任何责任。用户须对自己在网上的言论和行为承担法律责任。对于涉嫌违反法律法规、涉嫌违法犯罪的行为、生命力教育联盟平台将保存有关记录,并有权依法向有关主管部门报告、配合有关主管部门调查、向公安机关报案等。',
296 - ] 343 + ],
297 }, 344 },
298 { 345 {
299 title: '九、服务的变更、中断', 346 title: '九、服务的变更、中断',
300 content: [ 347 content: [
301 - '1、用户理解并同意,美乐爱觉平台提供的服务是按照现有技术和条件所能达到的现状提供的。用户亦明确知道使用服务存在一定信息风险,美乐爱觉平台将尽力维护用户使用服务的合法权益,但不担保服务一定能满足用户要求,也不担保服务的及时性、安全性、真实性、稳定性、正确性,对用户使用服务中出现的信息(包括但不限于用户发布的信息删除或存储失败),美乐爱觉平台为此不承担任何责任。', 348 + '1、用户理解并同意,生命力教育联盟平台提供的服务是按照现有技术和条件所能达到的现状提供的。用户亦明确知道使用服务存在一定信息风险,生命力教育联盟平台将尽力维护用户使用服务的合法权益,但不担保服务一定能满足用户要求,也不担保服务的及时性、安全性、真实性、稳定性、正确性,对用户使用服务中出现的信息(包括但不限于用户发布的信息删除或存储失败),生命力教育联盟平台为此不承担任何责任。',
302 - '2、用户理解并同意,美乐爱觉平台为了整体服务运营安全需要或定期或不定期地检测或者更新需要,有权视具体情况决定服务变更、中断、中止或终止服务,但美乐爱觉平台将尽可能事先进行通告。', 349 + '2、用户理解并同意,生命力教育联盟平台为了整体服务运营安全需要或定期或不定期地检测或者更新需要,有权视具体情况决定服务变更、中断、中止或终止服务,但生命力教育联盟平台将尽可能事先进行通告。',
303 - '3、用户理解并同意,鉴于网络服务的特殊性,服务可能会受到多种因素(包括但不限于境内外基础运营商的网络故障、技术缺陷、覆盖范围限制、不可抗力、计算机病毒、黑客攻击或其他非美乐爱觉平台技术能力范围内的事因等)的影响或干扰,美乐爱觉平台不能随时或始终预见和防范上述因素造成的服务中断、用户存储信息丢失、未保存、出现乱码、错误接收、无法接收、延迟接收等,美乐爱觉平台无需为此对任何用户或任何第三方承担责任。若发生上述因此,美乐爱觉平台将尽可能及时通过公告、系统通知等其他合理方式通知受到影响的用户。' 350 + '3、用户理解并同意,鉴于网络服务的特殊性,服务可能会受到多种因素(包括但不限于境内外基础运营商的网络故障、技术缺陷、覆盖范围限制、不可抗力、计算机病毒、黑客攻击或其他非生命力教育联盟平台技术能力范围内的事因等)的影响或干扰,生命力教育联盟平台不能随时或始终预见和防范上述因素造成的服务中断、用户存储信息丢失、未保存、出现乱码、错误接收、无法接收、延迟接收等,生命力教育联盟平台无需为此对任何用户或任何第三方承担责任。若发生上述因此,生命力教育联盟平台将尽可能及时通过公告、系统通知等其他合理方式通知受到影响的用户。',
304 - ] 351 + ],
305 }, 352 },
306 { 353 {
307 title: '十、知识产权条款', 354 title: '十、知识产权条款',
308 content: [ 355 content: [
309 - '1、北京美乐爱觉有限公司对本服务中所有内容,包括但不限于设计、画面安排、软件架构、图片、文章、视频等均由北京美乐爱觉有限公司依法拥有其知识产权(包括但不限于商标权、专利权、著作权、商业秘密等)。', 356 + '1、北京生命力教育联盟有限公司对本服务中所有内容,包括但不限于设计、画面安排、软件架构、图片、文章、视频等均由北京生命力教育联盟有限公司依法拥有其知识产权(包括但不限于商标权、专利权、著作权、商业秘密等)。',
310 - '2、非经北京美乐爱觉有限公司书面同意,任何人不得擅自使用、修改、复制、公开传播、改变、散布、发行或公开发表美乐爱觉平台程序或内容。', 357 + '2、非经北京生命力教育联盟有限公司书面同意,任何人不得擅自使用、修改、复制、公开传播、改变、散布、发行或公开发表生命力教育联盟平台程序或内容。',
311 - '3、尊重知识产权是用户应尽的义务,如有违反,应承担相应赔偿责任。' 358 + '3、尊重知识产权是用户应尽的义务,如有违反,应承担相应赔偿责任。',
312 - ] 359 + ],
313 }, 360 },
314 { 361 {
315 title: '十一、服务条款修改', 362 title: '十一、服务条款修改',
316 content: [ 363 content: [
317 - '1、美乐爱觉平台有权随时修改本服务条款的任何内容,一旦本服务条款的任何内容发生变动,美乐爱觉平台将会通过适当方式(包括但不限于弹窗)向用户提示修改内容。', 364 + '1、生命力教育联盟平台有权随时修改本服务条款的任何内容,一旦本服务条款的任何内容发生变动,生命力教育联盟平台将会通过适当方式(包括但不限于弹窗)向用户提示修改内容。',
318 - '2、如果不同意美乐爱觉平台对本服务条款所做的修改,用户有权停止使用本服务。', 365 + '2、如果不同意生命力教育联盟平台对本服务条款所做的修改,用户有权停止使用本服务。',
319 - '3、如果用户继续使用网络服务,则视为用户接受美乐爱觉平台对本服务条款所做的修改。' 366 + '3、如果用户继续使用网络服务,则视为用户接受生命力教育联盟平台对本服务条款所做的修改。',
320 - ] 367 + ],
321 }, 368 },
322 { 369 {
323 title: '十二、隐私保护', 370 title: '十二、隐私保护',
324 - content: [ 371 + content: ['请阅读《隐私保护政策》。'],
325 - '请阅读《隐私保护政策》。'
326 - ]
327 }, 372 },
328 { 373 {
329 title: '十三、其他', 374 title: '十三、其他',
330 content: [ 375 content: [
331 - '1、若美乐爱觉平台已经明示其服务提供方式发生变更并提醒用户应当注意事项,用户未按要求操作所产生的一切后果由用户自行承担。', 376 + '1、若生命力教育联盟平台已经明示其服务提供方式发生变更并提醒用户应当注意事项,用户未按要求操作所产生的一切后果由用户自行承担。',
332 - '2、用户同意保障和维护美乐爱觉平台及其他用户的利益,由于用户在使用美乐爱觉平台有违法、不真实、不正当、侵犯第三方合法权益的行为,或用户违反本协议项下的任何条款而给美乐爱觉平台及任何其他第三方造成损失,用户同意承担由此造成的损害赔偿责任。', 377 + '2、用户同意保障和维护生命力教育联盟平台及其他用户的利益,由于用户在使用生命力教育联盟平台有违法、不真实、不正当、侵犯第三方合法权益的行为,或用户违反本协议项下的任何条款而给生命力教育联盟平台及任何其他第三方造成损失,用户同意承担由此造成的损害赔偿责任。',
333 - '3、本协议的效力、解释及纠纷的解决,适用于中华人民共和国法律。若用户和美乐爱觉平台之间发生任何纠纷或争议,首先应友好协商解决,协商不成的,任何一方均有权向杭州南风教育科技有限公司住所地人民法院提起诉讼。', 378 + '3、本协议的效力、解释及纠纷的解决,适用于中华人民共和国法律。若用户和生命力教育联盟平台之间发生任何纠纷或争议,首先应友好协商解决,协商不成的,任何一方均有权向杭州南风教育科技有限公司住所地人民法院提起诉讼。',
334 '4、本协议的任何条款被司法部门认定为无效或不具可执行性,或违反所须适用的法律的,则该条款将被视为无效,其余条款仍然有效,对双方具有约束力。', 379 '4、本协议的任何条款被司法部门认定为无效或不具可执行性,或违反所须适用的法律的,则该条款将被视为无效,其余条款仍然有效,对双方具有约束力。',
335 - '5、本协议最终解释权归杭州南风教育科技有限公司所有。' 380 + '5、本协议最终解释权归杭州南风教育科技有限公司所有。',
336 - ] 381 + ],
337 }, 382 },
338 { 383 {
339 title: '十四、免责声明', 384 title: '十四、免责声明',
340 content: [ 385 content: [
341 - '1、用户明确同意其使用美乐爱觉平台服务,以及对美乐爱觉平台服务加以依赖所存在的全部责任和风险将完全有其自己承担,因其使用美乐爱觉平台服务过程的行为,以及因此而产生的一切后果也由其自己承担,美乐爱觉平台对用户不承担任何责任。', 386 + '1、用户明确同意其使用生命力教育联盟平台服务,以及对生命力教育联盟平台服务加以依赖所存在的全部责任和风险将完全有其自己承担,因其使用生命力教育联盟平台服务过程的行为,以及因此而产生的一切后果也由其自己承担,生命力教育联盟平台对用户不承担任何责任。',
342 - '2、美乐爱觉平台不担保服务一定能满足用户要求,也不担保服务不会中断,对服务的及时性、安全性、准确性也都不作担保。', 387 + '2、生命力教育联盟平台不担保服务一定能满足用户要求,也不担保服务不会中断,对服务的及时性、安全性、准确性也都不作担保。',
343 - '3、用户因使用本服务而产生的任何间接的、附带的、特殊的、结果性的或惩戒性的损害,美乐爱觉平台概不负责,均由用户自行承担。' 388 + '3、用户因使用本服务而产生的任何间接的、附带的、特殊的、结果性的或惩戒性的损害,生命力教育联盟平台概不负责,均由用户自行承担。',
344 - ] 389 + ],
345 - } 390 + },
346 ] 391 ]
347 </script> 392 </script>
348 393
......