搭子交友 app 动态分享与打卡系统设计实现

一、逻辑分析

  1. 动态分享模块
    • 用户输入动态内容:用户在 APP 中输入想要分享的文字、图片、视频等信息。这涉及到用户界面的设计,要确保输入的便捷性和友好性。例如,提供简洁的文本输入框,支持一键上传本地图片和视频等操作。
    • 动态存储:将用户输入的内容存储到数据库中。需要设计合适的数据库表结构来存储动态信息,包括动态 ID、用户 ID、发布时间、内容(文本、图片或视频的存储路径等)等字段。
    • 动态展示:从数据库中读取用户的动态信息,并在 APP 界面上展示给用户自己以及其他有权限查看的用户。展示部分要考虑不同类型内容(文字、图片、视频)的合理布局。
  2. 打卡系统模块
    • 打卡触发:用户在 APP 中点击打卡按钮触发打卡操作。打卡按钮的位置和样式要易于用户发现和操作。
    • 打卡记录存储:记录用户的打卡信息,如打卡时间、打卡地点(如果需要)、打卡类型(日常打卡、特殊任务打卡等)等,同样需要设计相应的数据库表结构来存储这些信息。
    • 打卡统计与展示:对用户的打卡数据进行统计,例如计算连续打卡天数、打卡频率等,并在 APP 界面上展示给用户,以激励用户持续打卡。

二、程序框架结构化输出

(一)后端框架
  1. 数据库设计
    • 动态表(Dynamic)

      sql

      复制代码
      CREATE TABLE Dynamic (
          dynamic_id INT AUTO_INCREMENT PRIMARY KEY,
          user_id INT NOT NULL,
          publish_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
          content TEXT,
          image_path VARCHAR(255),
          video_path VARCHAR(255),
          FOREIGN KEY (user_id) REFERENCES User(user_id)
      );
      • 解释:dynamic_id是动态的唯一标识。user_id关联发布动态的用户 ID。publish_time记录动态发布时间,默认使用当前时间戳。content存储文本内容,image_pathvideo_path分别存储图片和视频的路径。
    • 打卡记录表(CheckIn)

      sql

      复制代码
      CREATE TABLE CheckIn (
          check_in_id INT AUTO_INCREMENT PRIMARY KEY,
          user_id INT NOT NULL,
          check_in_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
          check_in_location VARCHAR(255),
          check_in_type VARCHAR(50),
          FOREIGN KEY (user_id) REFERENCES User(user_id)
      );
      • 解释:check_in_id是打卡记录的唯一标识。user_id关联打卡的用户 ID。check_in_time记录打卡时间,check_in_location存储打卡地点,check_in_type记录打卡类型。
  2. 用户认证与授权
    • 可以使用 JWT(JSON Web Token)进行用户认证。用户登录时,后端验证用户的用户名和密码,如果正确,生成 JWT 并返回给前端。前端在后续的请求中携带这个 JWT,后端通过验证 JWT 来确定用户身份。

    • 示例代码(以 Python Flask 框架为例): python

      复制代码
      import jwt
      from flask import Flask, request, jsonify
      from datetime import datetime, timedelta
      
      app = Flask(__name__)
      app.config['SECRET_KEY'] ='super_secret_key'
      
      def generate_token(user_id):
          payload = {
              'user_id': user_id,
              'exp': datetime.utcnow() + timedelta(hours=1)
          }
          token = jwt.encode(payload, app.config['SECRET_KEY'], algorithm='HS256')
          return token
      
      def verify_token(token):
          try:
              data = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256'])
              return data
          except jwt.ExpiredSignatureError:
              return None
          except jwt.InvalidTokenError:
              return None
      
      @app.route('/login', methods=['POST'])
      def login():
          data = request.get_json()
          username = data.get('username')
          password = data.get('password')
          # 这里应该有数据库查询验证用户名和密码的逻辑
          user_id = 1  # 假设验证通过返回的用户ID
          token = generate_token(user_id)
          return jsonify({'token': token})
      
      @app.route('/protected', methods=['GET'])
      def protected():
          token = request.headers.get('Authorization')
          if not token:
              return jsonify({'message': 'Token is missing'}), 401
          token = token.replace('Bearer ', '')
          data = verify_token(token)
          if not data:
              return jsonify({'message': 'Invalid token'}), 401
          return jsonify({'message': 'This is a protected route'})
      
      
      if __name__ == '__main__':
          app.run(debug=True)
      • 代码解释:generate_token函数生成 JWT,包含用户 ID 和过期时间。verify_token函数用于验证 JWT 的有效性。login路由处理用户登录请求,验证用户名和密码后生成并返回 JWT。protected路由是一个示例的受保护路由,验证请求中携带的 JWT。
  3. 动态分享功能实现
    • 创建动态 API

      python

      复制代码
      from flask import request, jsonify
      
      @app.route('/create_dynamic', methods=['POST'])
      def create_dynamic():
          token = request.headers.get('Authorization')
          if not token:
              return jsonify({'message': 'Token is missing'}), 401
          token = token.replace('Bearer ', '')
          data = verify_token(token)
          if not data:
              return jsonify({'message': 'Invalid token'}), 401
      
          user_id = data['user_id']
          content = request.form.get('content')
          image_file = request.files.get('image')
          video_file = request.files.get('video')
      
          # 处理图片和视频上传,保存到指定路径并获取路径
          image_path = None
          if image_file:
              image_path = save_image(image_file)
          video_path = None
          if video_file:
              video_path = save_video(video_file)
      
          # 插入动态到数据库
          cursor = connection.cursor()
          sql = "INSERT INTO Dynamic (user_id, content, image_path, video_path) VALUES (%s, %s, %s, %s)"
          cursor.execute(sql, (user_id, content, image_path, video_path))
          connection.commit()
          return jsonify({'message': 'Dynamic created successfully'})
      
      
      def save_image(image_file):
          # 实现保存图片到指定目录并返回路径的逻辑
          import os
          upload_dir = 'uploads/images'
          if not os.path.exists(upload_dir):
              os.makedirs(upload_dir)
          image_name = os.path.join(upload_dir, image_file.filename)
          image_file.save(image_name)
          return image_name
      
      
      def save_video(video_file):
          # 实现保存视频到指定目录并返回路径的逻辑
          import os
          upload_dir = 'uploads/videos'
          if not os.path.exists(upload_dir):
              os.makedirs(upload_dir)
          video_name = os.path.join(upload_dir, video_file.filename)
          video_file.save(video_name)
          return video_name
      • 代码解释:create_dynamic路由处理创建动态的请求。首先验证 JWT,获取用户 ID。然后从请求中获取文本内容、图片和视频文件。调用save_imagesave_video函数保存图片和视频并获取路径,最后将动态信息插入数据库。
    • 获取动态 API

      python

      复制代码
      @app.route('/get_dynamics', methods=['GET'])
      def get_dynamics():
          token = request.headers.get('Authorization')
          if not token:
              return jsonify({'message': 'Token is missing'}), 401
          token = token.replace('Bearer ', '')
          data = verify_token(token)
          if not data:
              return jsonify({'message': 'Invalid token'}), 401
      
          cursor = connection.cursor()
          sql = "SELECT * FROM Dynamic"
          cursor.execute(sql)
          dynamics = cursor.fetchall()
          result = []
          for dynamic in dynamics:
              dynamic_dict = {
                  'dynamic_id': dynamic[0],
                  'user_id': dynamic[1],
                  'publish_time': str(dynamic[2]),
                  'content': dynamic[3],
                  'image_path': dynamic[4],
                  'video_path': dynamic[5]
              }
              result.append(dynamic_dict)
          return jsonify(result)
      • 代码解释:get_dynamics路由用于获取所有动态。验证 JWT 后,从数据库中查询所有动态记录,并将其整理成字典形式返回给前端。
  4. 打卡系统功能实现
    • 打卡 API

      python

      复制代码
      @app.route('/check_in', methods=['POST'])
      def check_in():
          token = request.headers.get('Authorization')
          if not token:
              return jsonify({'message': 'Token is missing'}), 401
          token = token.replace('Bearer ', '')
          data = verify_token(token)
          if not data:
              return jsonify({'message': 'Invalid token'}), 401
      
          user_id = data['user_id']
          check_in_location = request.form.get('location')
          check_in_type = request.form.get('type')
      
          cursor = connection.cursor()
          sql = "INSERT INTO CheckIn (user_id, check_in_location, check_in_type) VALUES (%s, %s, %s)"
          cursor.execute(sql, (user_id, check_in_location, check_in_type))
          connection.commit()
          return jsonify({'message': 'Check-in successful'})
      • 代码解释:check_in路由处理打卡请求。验证 JWT 后,获取用户 ID、打卡地点和打卡类型,将打卡信息插入数据库。
    • 获取打卡统计 API

      python

      复制代码
      @app.route('/get_check_in_stats', methods=['GET'])
      def get_check_in_stats():
          token = request.headers.get('Authorization')
          if not token:
              return jsonify({'message': 'Token is missing'}), 401
          token = token.replace('Bearer ', '')
          data = verify_token(token)
          if not data:
              return jsonify({'message': 'Invalid token'}), 401
      
          user_id = data['user_id']
          cursor = connection.cursor()
      
          # 获取连续打卡天数
          sql1 = "SELECT COUNT(*) FROM (SELECT 1 FROM CheckIn WHERE user_id = %s AND check_in_time >= CURDATE() - INTERVAL (COUNT(*) - 1) DAY GROUP BY check_in_time) AS subquery"
          cursor.execute(sql1, (user_id,))
          consecutive_days = cursor.fetchone()[0]
      
          # 获取打卡频率
          sql2 = "SELECT COUNT(*) FROM CheckIn WHERE user_id = %s"
          cursor.execute(sql2, (user_id,))
          total_check_ins = cursor.fetchone()[0]
          # 假设统计周期为一个月
          frequency = total_check_ins / 30
      
          result = {
              'consecutive_days': consecutive_days,
              'frequency': frequency
          }
          return jsonify(result)
      • 代码解释:get_check_in_stats路由用于获取打卡统计信息。验证 JWT 后,通过 SQL 查询计算用户的连续打卡天数和打卡频率,并将结果返回给前端。
(二)前端框架(以 React Native 为例)
  1. 动态分享页面

    • 组件结构

      jsx

      复制代码
      import React, { useState } from'react';
      import { View, TextInput, Button, Image, Video, StyleSheet } from'react-native';
      
      const DynamicShareScreen = () => {
          const [content, setContent] = useState('');
          const [imageUri, setImageUri] = useState(null);
          const [videoUri, setVideoUri] = useState(null);
      
          const handleContentChange = (text) => {
              setContent(text);
          };
      
          const handleImageSelect = (uri) => {
              setImageUri(uri);
          };
      
          const handleVideoSelect = (uri) => {
              setVideoUri(uri);
          };
      
          const handleSubmit = () => {
              // 发送请求到后端创建动态
              // 这里需要引入网络请求库,如axios
              // 示例代码:
              // import axios from 'axios';
              // axios.post('http://localhost:5000/create_dynamic', {
              //     content: content,
              //     image: imageUri,
              //     video: videoUri
              // })
              //.then(response => {
              //     console.log(response.data.message);
              // })
              //.catch(error => {
              //     console.error('Error creating dynamic:', error);
              // });
          };
      
          return (
              <View style={styles.container}>
                  <TextInput
                      placeholder="Enter your dynamic content"
                      value={content}
                      onChangeText={handleContentChange}
                      style={styles.input}
                  />
                  {imageUri && <Image source={{ uri: imageUri }} style={styles.image} />}
                  {videoUri && <Video source={{ uri: videoUri }} style={styles.video} />}
                  <Button title="Select Image" onPress={() => selectImage(handleImageSelect)} />
                  <Button title="Select Video" onPress={() => selectVideo(handleVideoSelect)} />
                  <Button title="Submit" onPress={handleSubmit} />
              </View>
          );
      };
      
      const styles = StyleSheet.create({
          container: {
              padding: 20
          },
          input: {
              borderWidth: 1,
              borderColor: 'gray',
              padding: 10,
              marginBottom: 10
          },
          image: {
              width: 200,
              height: 200,
              marginBottom: 10
          },
          video: {
              width: 200,
              height: 200,
              marginBottom: 10
          }
      });
      
      const selectImage = (callback) => {
          // 实现选择图片并返回图片路径的逻辑
          // 可以使用react-native-image-picker库
          // 示例代码:
          // import ImagePicker from'react-native-image-picker';
          // ImagePicker.launchImageLibrary(options, (response) => {
          //     if (response.didCancel) {
          //         console.log('User cancelled image picker');
          //     } else if (response.error) {
          //         console.log('Image picker error:', response.error);
          //     } else if (response.assets) {
          //         const uri = response.assets[0].uri;
          //         callback(uri);
          //     }
          // });
      };
      
      const selectVideo = (callback) => {
          // 实现选择视频并返回视频路径的逻辑
          // 可以使用react-native-video-picker库
          // 示例代码:
          // import VideoPicker from'react-native-video-picker';
          // VideoPicker.openPicker(options, (response) => {
          //     if (response.didCancel) {
          //         console.log('User cancelled video picker');
          //     } else if (response.error) {
          //         console.log('Video picker error:', response.error);
          //     } else if (response.assets) {
          //         const uri = response.assets[0].uri;
          //         callback(uri);
          //     }
          // });
      };
      
      export default DynamicShareScreen;
    • 代码解释:DynamicShareScreen组件用于动态分享页面。useState钩子用于管理文本内容、图片路径和视频路径的状态。handleContentChange等函数处理用户输入和选择操作。handleSubmit函数用于发送请求到后端创建动态(这里只是示例,实际需要引入网络请求库并配置正确的 API 地址)。selectImageselectVideo函数用于实现选择图片和视频的功能(同样是示例,需要引入相应的库并正确配置)。

  2. 打卡页面

    • 组件结构

      jsx

      复制代码
      import React from'react';
      import { View, Button, StyleSheet } from'react-native';
      
      const CheckInScreen = () => {
          const handleCheckIn = () => {
              // 发送请求到后端打卡
              // 示例代码:
              // import axios from 'axios';
              // axios.post('http://localhost:5000/check_in', {
              //     location: 'Some location',
              //     type: 'Daily check-in'
              // })
              //.then(response => {
              //     console.log(response.data.message);
              // })
              //.catch(error => {
              //     console.error('Error checking in:', error);
              // });
          };
      
          return (
              <View style={styles.container}>
                  <Button title="Check In" onPress={handleCheckIn} />
              </View>
          );
      };
      
      const styles = StyleSheet.create({
          container: {
              justifyContent: 'center',
              alignItems: 'center',
              flex: 1
          }
      });
      
      export default CheckInScreen;
    • 代码解释:CheckInScreen组件用于打卡页面。handleCheckIn函数用于发送请求到后端进行打卡操作(同样是示例,需要引入网络请求库并配置正确)

    三、提供解决方案

    (一)代码示例及解释

    动态展示页面

    jsx

    复制代码
      import React, { useState, useEffect } from'react';
      import { View, FlatList, Text, Image, Video, StyleSheet } from'react-native';
      import axios from 'axios';
    
      const DynamicListScreen = () => {
          const [dynamics, setDynamics] = useState([]);
    
          useEffect(() => {
              const fetchDynamics = async () => {
                  try {
                      const response = await axios.get('http://localhost:5000/get_dynamics');
                      setDynamics(response.data);
                  } catch (error) {
                      console.error('Error fetching dynamics:', error);
                  }
              };
              fetchDynamics();
          }, []);
    
          const renderDynamic = ({ item }) => {
              return (
                  <View style={styles.dynamicContainer}>
                      <Text>{item.content}</Text>
                      {item.image_path && <Image source={{ uri: item.image_path }} style={styles.image} />}
                      {item.video_path && <Video source={{ uri: item.video_path }} style={styles.video} />}
                  </View>
              );
          };
    
          return (
              <View style={styles.container}>
                  <FlatList
                      data={dynamics}
                      renderItem={renderDynamic}
                      keyExtractor={(item) => item.dynamic_id.toString()}
                  />
              </View>
          );
      };
    
      const styles = StyleSheet.create({
          container: {
              padding: 20
          },
          dynamicContainer: {
              borderWidth: 1,
              borderColor: 'gray',
              padding: 10,
              marginBottom: 10
          },
          image: {
              width: 200,
              height: 200,
              marginBottom: 10
          },
          video: {
              width: 200,
              height: 200,
              marginBottom: 10
          }
      });
    
      export default DynamicListScreen;

    代码解释:

    • DynamicListScreen组件用于展示动态列表。

    • useState钩子用于存储动态数据。

    • useEffect钩子在组件挂载时执行一次,通过axios发送GET请求到后端获取动态数据,并更新dynamics状态。

    • renderDynamic函数用于渲染每个动态项,根据动态数据中的图片和视频路径展示相应的内容。

    • FlatList用于高效渲染动态列表,data属性指定数据源,renderItem属性指定渲染每个列表项的函数,keyExtractor属性为每个列表项提供唯一的键。

    • 打卡统计页面

      jsx

      复制代码
      import React, { useState, useEffect } from'react';
      import { View, Text, StyleSheet } from'react-native';
      import axios from 'axios';
      
      const CheckInStatsScreen = () => {
          const [stats, setStats] = useState({});
      
          useEffect(() => {
              const fetchStats = async () => {
                  try {
                      const response = await axios.get('http://localhost:5000/get_check_in_stats');
                      setStats(response.data);
                  } catch (error) {
                      console.error('Error fetching check-in stats:', error);
                  }
              };
              fetchStats();
          }, []);
      
          return (
              <View style={styles.container}>
                  <Text>Consecutive Check-in Days: {stats.consecutive_days}</Text>
                  <Text>Check-in Frequency: {stats.frequency}</Text>
              </View>
          );
      };
      
      const styles = StyleSheet.create({
          container: {
              justifyContent: 'center',
              alignItems: 'center',
              flex: 1
          }
      });
      
      export default CheckInStatsScreen;

      代码解释:

    • CheckInStatsScreen组件用于展示打卡统计信息。

    • useState钩子用于存储打卡统计数据。

    • useEffect钩子在组件挂载时执行一次,通过axios发送GET请求到后端获取打卡统计数据,并更新stats状态。

    • 组件返回的View中展示了连续打卡天数和打卡频率。

    (二)整体总结
    • 功能实现
      • 本设计实现了搭子交友 APP 的动态分享与打卡系统的核心功能。动态分享模块允许用户输入文字、上传图片和视频并分享,同时其他用户可以查看这些动态。打卡系统模块支持用户打卡,并能统计连续打卡天数和打卡频率等信息。
    • 技术架构
      • 后端:采用 Python 的 Flask 框架搭建服务器,通过 SQLite 数据库存储动态和打卡相关数据。使用 JWT 进行用户认证,确保系统的安全性。各个功能模块都有对应的 API 接口,实现了前后端的数据交互。
      • 前端:以 React Native 框架构建 APP 界面,通过状态管理和网络请求实现用户交互和数据获取展示。不同的页面组件分别负责动态分享、打卡、动态展示和打卡统计等功能的界面呈现。
    • 优化方向
      • 性能优化:在实际应用中,随着数据量的增加,需要对数据库查询和网络请求进行优化。例如,对频繁查询的动态数据可以采用缓存机制,减少数据库的负载。
      • 用户体验优化:可以进一步完善界面设计,增加加载动画、提示信息等,提高用户操作的流畅性和友好性。
      • 安全优化:除了 JWT 认证,还可以考虑增加其他安全措施,如数据加密传输、防止 SQL 注入攻击等,保障用户数据的安全。
    • 通过上述设计和实现,搭子交友 APP 的动态分享与打卡系统能够满足用户在社交互动和自我激励方面的需求,并且具有一定的可扩展性和优化空间。
相关推荐
彬彬醤8 分钟前
Mac怎么连接VPS?可以参考这几种方法
大数据·运维·服务器·数据库·线性代数·macos·矩阵
qq_262498119 分钟前
Datawhale AI夏令营---coze空间共学
人工智能
vvilkim13 分钟前
深入理解 Spring Boot Starter:简化依赖管理与自动配置的利器
java·前端·spring boot
废喵喵呜13 分钟前
达梦数据库-实时主备集群部署详解(附图文)手工搭建一主一备数据守护集群DW
网络·数据库·tcp/ip
失散1316 分钟前
自然语言处理——04 注意力机制
人工智能·自然语言处理·注意力机制·seq2seq 架构
柯南二号20 分钟前
【Java后端】【可直接落地的 Redis 分布式锁实现】
java·redis·分布式
卑微的小鬼1 小时前
如何保证数据库和缓存的一致性?
数据库·缓存
MiaoChuAI1 小时前
豆包AI PPT与秒出PPT对比评测:谁更适合你?
人工智能·powerpoint
1点东西1 小时前
新来的同事问我当进程/机器突然停止时,finally 到底会不会执行?
java·后端·程序员
做一个AC梦1 小时前
MiniOB环境部署开发(使用Docker)
数据库·sql·miniob·ob·海扬数据库