盛世宏图 发表于 2025-4-4 02:08:50

开发体育赛事直播体系主播认证功能技术实现方案

该体育直播体系体系由东莞梦幻网络科技开发,使用 ThinkPHP 作为后端,Vue.js 作为 PC/H5 端框架,Java 和 Objective-C 分别用于安卓和 iOS 开发。
1、前端实现 (Vue.js)

<template>
<div class="anchor-certification">
    <div class="header">
      <h1>主播认证</h1>
    </div>
   
    <div class="form-container">
      <el-form :model="form" :rules="rules" ref="form" label-width="120px">
      <!-- 直播信息 -->
      <el-form-item label="直播赛事" prop="liveType">
          <el-checkbox-group v-model="form.liveType">
            <el-checkbox label="足球"></el-checkbox>
            <el-checkbox label="篮球"></el-checkbox>
            <el-checkbox label="电竞"></el-checkbox>
            <el-checkbox label="其他"></el-checkbox>
          </el-checkbox-group>
      </el-form-item>
      
      <el-form-item label="直播经验" prop="experience">
          <el-select v-model="form.experience" placeholder="请选择">
            <el-option label="1个月" value="1"></el-option>
            <el-option label="3个月" value="3"></el-option>
            <el-option label="6个月" value="6"></el-option>
            <el-option label="1年" value="12"></el-option>
            <el-option label="2年" value="24"></el-option>
            <el-option label="3年以上" value="36"></el-option>
          </el-select>
      </el-form-item>
      
      <!-- 个人信息 -->
      <el-form-item label="姓名" prop="realName">
          <el-input v-model="form.realName" placeholder="请输入您的真实姓名"></el-input>
      </el-form-item>
      
      <el-form-item label="身份证号" prop="idCard">
          <el-input v-model="form.idCard" placeholder="请输入您身份证号码"></el-input>
      </el-form-item>
      
      <el-form-item label="身份照片" prop="idCardPhoto">
          <el-upload
            action="/api/upload/idCard"
            :limit="1"
            :on-success="handleIdCardSuccess"
            :before-upload="beforeIdCardUpload"
            :file-list="idCardFileList">
            <el-button size="small" type="primary">点击上传</el-button>
            <div slot="tip" class="el-upload__tip">请上传身份证正面照片,支持jpg/png格式,大小不超过5MB</div>
          </el-upload>
      </el-form-item>
      
      <!-- 联系方式 -->
      <el-form-item label="联系方式">
          <el-input v-model="form.qq" placeholder="QQ号"></el-input>
          <el-input v-model="form.wechat" placeholder="微信号"></el-input>
          <el-input v-model="form.phone" placeholder="电话号码"></el-input>
      </el-form-item>
      
      <!-- 个人简介 -->
      <el-form-item label="个人简介" prop="introduction">
          <el-input
            type="textarea"
            :rows="5"
            v-model="form.introduction"
            placeholder="请填写您的个人简介,不少于15字"
            :minlength="15">
          </el-input>
          <div class="intro-tips">
            <p>建议包含以下内容:</p>
            <p>1. 主播经验几年</p>
            <p>2. 在哪些平台上担任过主播</p>
            <p>3. 曾经获得过哪些荣誉</p>
            <p>4. 擅长直播哪类赛事(足球、篮球、电竞、娱乐、其他)</p>
          </div>
      </el-form-item>
      
      <!-- 邀请人 -->
      <el-form-item label="邀请人">
          <el-input v-model="form.inviter" placeholder="请输入邀请人(选填)"></el-input>
          <el-input v-model="form.inviterPhone" placeholder="+86 请输入邀请人电话(选填)"></el-input>
      </el-form-item>
      
      <!-- 验证码 -->
      <el-form-item label="验证码" prop="captcha">
          <el-input v-model="form.captcha" placeholder="请输入验证码" style="width: 200px"></el-input>
          <el-button @click="getCaptcha" :disabled="captchaDisabled">
            {{ captchaBtnText }}
          </el-button>
      </el-form-item>
      
      <!-- 协议 -->
      <el-form-item prop="agreed">
          <el-checkbox v-model="form.agreed">
            我已阅读并同意<a href="/protocol/anchor" target="_blank">《体育直播协议》</a>
          </el-checkbox>
      </el-form-item>
      
      <!-- 提交按钮 -->
      <el-form-item>
          <el-button type="primary" @click="submitForm" :loading="submitting">提交认证</el-button>
      </el-form-item>
      </el-form>
    </div>
   
    <div class="footer">
      <div class="links">
      <a href="#">关于我们</a>
      <a href="#">联系方式</a>
      <a href="#">帮助中心</a>
      </div>
      <div class="copyright">
      Copyright © 2020-2025 龙牙直播 ALL Rights Reserved
      </div>
    </div>
</div>
</template>

<script>
export default {
data() {
    return {
      form: {
      liveType: [],
      experience: '',
      realName: '',
      idCard: '',
      idCardPhoto: '',
      qq: '',
      wechat: '',
      phone: '',
      introduction: '',
      inviter: '',
      inviterPhone: '',
      captcha: '',
      agreed: false
      },
      rules: {
      liveType: [
          { type: 'array', required: true, message: '请至少选择一项直播赛事', trigger: 'change' }
      ],
      experience: [
          { required: true, message: '请选择直播经验', trigger: 'change' }
      ],
      realName: [
          { required: true, message: '请输入真实姓名', trigger: 'blur' }
      ],
      idCard: [
          { required: true, message: '请输入身份证号码', trigger: 'blur' },
          { pattern: /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/, message: '身份证号格式不正确' }
      ],
      idCardPhoto: [
          { required: true, message: '请上传身份证照片', trigger: 'blur' }
      ],
      introduction: [
          { required: true, message: '请输入个人简介', trigger: 'blur' },
          { min: 15, message: '个人简介不能少于15个字符', trigger: 'blur' }
      ],
      captcha: [
          { required: true, message: '请输入验证码', trigger: 'blur' }
      ],
      agreed: [
          { validator: (rule, value, callback) => {
            if (!value) {
                callback(new Error('请阅读并同意协议'));
            } else {
                callback();
            }
            }, trigger: 'change' }
      ]
      },
      idCardFileList: [],
      captchaDisabled: false,
      captchaBtnText: '获取验证码',
      countdown: 60,
      submitting: false
    };
},
methods: {
    handleIdCardSuccess(response, file) {
      this.form.idCardPhoto = response.data.url;
    },
    beforeIdCardUpload(file) {
      const isJPG = file.type === 'image/jpeg' || file.type === 'image/png';
      const isLt5M = file.size / 1024 / 1024 < 5;
      
      if (!isJPG) {
      this.$message.error('上传头像图片只能是 JPG/PNG 格式!');
      }
      if (!isLt5M) {
      this.$message.error('上传头像图片大小不能超过 5MB!');
      }
      return isJPG && isLt5M;
    },
    getCaptcha() {
      if (!this.form.phone) {
      this.$message.error('请输入手机号码');
      return;
      }
      
      // 调用API获取验证码
      this.$http.post('/api/captcha/sms', { phone: this.form.phone })
      .then(() => {
          this.$message.success('验证码已发送');
          this.startCountdown();
      })
      .catch(error => {
          this.$message.error(error.message || '验证码发送失败');
      });
    },
    startCountdown() {
      this.captchaDisabled = true;
      this.captchaBtnText = `${this.countdown}秒后重新获取`;
      
      const timer = setInterval(() => {
      this.countdown -= 1;
      this.captchaBtnText = `${this.countdown}秒后重新获取`;
      
      if (this.countdown <= 0) {
          clearInterval(timer);
          this.captchaDisabled = false;
          this.captchaBtnText = '获取验证码';
          this.countdown = 60;
      }
      }, 1000);
    },
    submitForm() {
      this.$refs.form.validate(valid => {
      if (valid) {
          this.submitting = true;
         
          this.$http.post('/api/anchor/certification', this.form)
            .then(response => {
            this.$message.success('提交成功,请等待审核');
            this.$router.push('/certification/result');
            })
            .catch(error => {
            this.$message.error(error.message || '提交失败');
            })
            .finally(() => {
            this.submitting = false;
            });
      } else {
          return false;
      }
      });
    }
}
};
</script>

<style scoped>
.anchor-certification {
max-width: 800px;
margin: 0 auto;
padding: 20px;
}

.header {
text-align: center;
margin-bottom: 30px;
}

.form-container {
background: #fff;
padding: 30px;
border-radius: 5px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}

.intro-tips {
color: #999;
font-size: 12px;
margin-top: 5px;
}

.footer {
margin-top: 30px;
text-align: center;
color: #999;
font-size: 12px;
}

.links {
margin-bottom: 10px;
}

.links a {
margin: 0 10px;
color: #999;
text-decoration: none;
}

.links a:hover {
color: #409EFF;
}
</style>
2、后端实现 (PHP/ThinkPHP)

<?php
namespace app\api\controller;

use think\Controller;
use think\Request;
use think\Validate;

class AnchorCertification extends Controller
{
    // 提交主播认证
    public function submit()
    {
      $request = Request::instance();
      $data = $request->post();
      
      // 验证规则
      $rules = [
            'liveType' => 'require|array',
            'experience' => 'require',
            'realName' => 'require|chs',
            'idCard' => 'require|idCard',
            'idCardPhoto' => 'require|url',
            'introduction' => 'require|min:15',
            'captcha' => 'require',
            'agreed' => 'require|accepted'
      ];
      
      // 验证消息
      $messages = [
            'liveType.require' => '请选择直播赛事',
            'experience.require' => '请选择直播经验',
            'realName.require' => '请输入真实姓名',
            'realName.chs' => '姓名只能为中文',
            'idCard.require' => '请输入身份证号码',
            'idCard.idCard' => '身份证号格式不正确',
            'idCardPhoto.require' => '请上传身份证照片',
            'idCardPhoto.url' => '身份证照片URL格式不正确',
            'introduction.require' => '请输入个人简介',
            'introduction.min' => '个人简介不能少于15个字符',
            'captcha.require' => '请输入验证码',
            'agreed.require' => '请阅读并同意协议',
            'agreed.accepted' => '请阅读并同意协议'
      ];
      
      $validate = new Validate($rules, $messages);
      
      if (!$validate->check($data)) {
            return json([
                'code' => 400,
                'message' => $validate->getError()
            ]);
      }
      
      // 验证验证码
      if (!$this->checkCaptcha($data['phone'], $data['captcha'])) {
            return json([
                'code' => 400,
                'message' => '验证码错误或已过期'
            ]);
      }
      
      // 保存认证信息
      $certification = [
            'user_id' => $request->userId, // 从token中获取的用户ID
            'live_type' => implode(',', $data['liveType']),
            'experience' => $data['experience'],
            'real_name' => $data['realName'],
            'id_card' => $data['idCard'],
            'id_card_photo' => $data['idCardPhoto'],
            'qq' => $data['qq'] ?? '',
            'wechat' => $data['wechat'] ?? '',
            'phone' => $data['phone'] ?? '',
            'introduction' => $data['introduction'],
            'inviter' => $data['inviter'] ?? '',
            'inviter_phone' => $data['inviterPhone'] ?? '',
            'status' => 0, // 0-待审核 1-已通过 2-已拒绝
            'create_time' => time(),
            'update_time' => time()
      ];
      
      try {
            $id = db('anchor_certification')->insertGetId($certification);
            
            return json([
                'code' => 200,
                'message' => '提交成功,请等待审核',
                'data' => ['id' => $id]
            ]);
      } catch (\Exception $e) {
            return json([
                'code' => 500,
                'message' => '提交失败: ' . $e->getMessage()
            ]);
      }
    }
   
    // 获取验证码
    public function sendCaptcha()
    {
      $request = Request::instance();
      $phone = $request->post('phone');
      
      if (empty($phone)) {
            return json([
                'code' => 400,
                'message' => '请输入手机号码'
            ]);
      }
      
      if (!preg_match('/^1\d{9}$/', $phone)) {
            return json([
                'code' => 400,
                'message' => '手机号码格式不正确'
            ]);
      }
      
      // 生成验证码
      $captcha = mt_rand(100000, 999999);
      
      // 保存验证码到缓存,有效期5分钟
      cache('captcha_' . $phone, $captcha, 300);
      
      // TODO: 实际项目中这里应该调用短信服务发送验证码
      // $this->sendSms($phone, $captcha);
      
      return json([
            'code' => 200,
            'message' => '验证码已发送'
      ]);
    }
   
    // 验证验证码
    private function checkCaptcha($phone, $captcha)
    {
      $cacheCaptcha = cache('captcha_' . $phone);
      
      if ($cacheCaptcha && $cacheCaptcha == $captcha) {
            // 验证成功后删除验证码
            cache('captcha_' . $phone, null);
            return true;
      }
      
      return false;
    }
   
    // 上传身份证照片
    public function uploadIdCard()
    {
      $file = request()->file('file');
      
      if (empty($file)) {
            return json([
                'code' => 400,
                'message' => '请选择上传文件'
            ]);
      }
      
      // 验证文件类型和大小
      $info = $file->validate([
            'size' => 5242880, // 5MB
            'ext' => 'jpg,jpeg,png'
      ])->move(ROOT_PATH . 'public' . DS . 'uploads' . DS . 'idcards');
      
      if ($info) {
            $url = '/uploads/idcards/' . $info->getSaveName();
            
            return json([
                'code' => 200,
                'message' => '上传成功',
                'data' => ['url' => $url]
            ]);
      } else {
            return json([
                'code' => 400,
                'message' => $file->getError()
            ]);
      }
    }
}
3、安卓实现 (Java)

// AnchorCertificationActivity.java
public class AnchorCertificationActivity extends AppCompatActivity {
    private EditText etRealName, etIdCard, etQQ, etWechat, etPhone, etIntroduction, etInviter, etInviterPhone, etCaptcha;
    private CheckBox cbFootball, cbBasketball, cbEsports, cbOther;
    private Spinner spExperience;
    private ImageView ivIdCard;
    private Button btnGetCaptcha, btnSubmit;
    private CheckBox cbAgree;
   
    private String idCardPhotoUrl;
    private int countdown = 60;
    private boolean isCountdownRunning = false;
   
    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_anchor_certification);
      
      initViews();
      setupSpinner();
    }
   
    private void initViews() {
      etRealName = findViewById(R.id.et_real_name);
      etIdCard = findViewById(R.id.et_id_card);
      etQQ = findViewById(R.id.et_qq);
      etWechat = findViewById(R.id.et_wechat);
      etPhone = findViewById(R.id.et_phone);
      etIntroduction = findViewById(R.id.et_introduction);
      etInviter = findViewById(R.id.et_inviter);
      etInviterPhone = findViewById(R.id.et_inviter_phone);
      etCaptcha = findViewById(R.id.et_captcha);
      
      cbFootball = findViewById(R.id.cb_football);
      cbBasketball = findViewById(R.id.cb_basketball);
      cbEsports = findViewById(R.id.cb_esports);
      cbOther = findViewById(R.id.cb_other);
      
      spExperience = findViewById(R.id.sp_experience);
      
      ivIdCard = findViewById(R.id.iv_id_card);
      ivIdCard.setOnClickListener(v -> uploadIdCard());
      
      btnGetCaptcha = findViewById(R.id.btn_get_captcha);
      btnGetCaptcha.setOnClickListener(v -> getCaptcha());
      
      btnSubmit = findViewById(R.id.btn_submit);
      btnSubmit.setOnClickListener(v -> submitCertification());
      
      cbAgree = findViewById(R.id.cb_agree);
    }
   
    private void setupSpinner() {
      ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,
                R.array.experience_options, android.R.layout.simple_spinner_item);
      adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
      spExperience.setAdapter(adapter);
    }
   
    private void uploadIdCard() {
      Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
      intent.setType("image/*");
      startActivityForResult(intent, 1);
    }
   
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
      super.onActivityResult(requestCode, resultCode, data);
      
      if (requestCode == 1 && resultCode == RESULT_OK && data != null) {
            Uri uri = data.getData();
            try {
                Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
                ivIdCard.setImageBitmap(bitmap);
               
                // 实际上传逻辑
                uploadImageToServer(uri);
            } catch (IOException e) {
                e.printStackTrace();
                Toast.makeText(this, "图片加载失败", Toast.LENGTH_SHORT).show();
            }
      }
    }
   
    private void uploadImageToServer(Uri uri) {
      // 这里实现实际上传逻辑,使用OkHttp或其他网络库
      // 上传成功后保存返回的URL到idCardPhotoUrl
    }
   
    private void getCaptcha() {
      String phone = etPhone.getText().toString().trim();
      
      if (phone.isEmpty()) {
            Toast.makeText(this, "请输入手机号码", Toast.LENGTH_SHORT).show();
            return;
      }
      
      if (!Patterns.PHONE.matcher(phone).matches()) {
            Toast.makeText(this, "手机号码格式不正确", Toast.LENGTH_SHORT).show();
            return;
      }
      
      // 调用API获取验证码
      getCaptchaFromServer(phone);
      
      // 开始倒计时
      startCountdown();
    }
   
    private void getCaptchaFromServer(String phone) {
      // 使用Retrofit或Volley调用API
      // 成功回调后显示提示
      Toast.makeText(this, "验证码已发送", Toast.LENGTH_SHORT).show();
    }
   
    private void startCountdown() {
      isCountdownRunning = true;
      btnGetCaptcha.setEnabled(false);
      
      new CountDownTimer(60000, 1000) {
            @Override
            public void onTick(long millisUntilFinished) {
                btnGetCaptcha.setText(countdown + "秒后重新获取");
                countdown--;
            }
            
            @Override
            public void onFinish() {
                btnGetCaptcha.setEnabled(true);
                btnGetCaptcha.setText("获取验证码");
                countdown = 60;
                isCountdownRunning = false;
            }
      }.start();
    }
   
    private void submitCertification() {
      String realName = etRealName.getText().toString().trim();
      String idCard = etIdCard.getText().toString().trim();
      String introduction = etIntroduction.getText().toString().trim();
      String captcha = etCaptcha.getText().toString().trim();
      
      // 验证必填项
      if (realName.isEmpty()) {
            Toast.makeText(this, "请输入真实姓名", Toast.LENGTH_SHORT).show();
            return;
      }
      
      if (idCard.isEmpty() || !validateIdCard(idCard)) {
            Toast.makeText(this, "请输入正确的身份证号码", Toast.LENGTH_SHORT).show();
            return;
      }
      
      if (idCardPhotoUrl == null || idCardPhotoUrl.isEmpty()) {
            Toast.makeText(this, "请上传身份证照片", Toast.LENGTH_SHORT).show();
            return;
      }
      
      if (introduction.isEmpty() || introduction.length() < 15) {
            Toast.makeText(this, "个人简介不能少于15字", Toast.LENGTH_SHORT).show();
            return;
      }
      
      if (captcha.isEmpty()) {
            Toast.makeText(this, "请输入验证码", Toast.LENGTH_SHORT).show();
            return;
      }
      
      if (!cbAgree.isChecked()) {
            Toast.makeText(this, "请阅读并同意协议", Toast.LENGTH_SHORT).show();
            return;
      }
      
      // 收集直播类型
      List<String> liveTypes = new ArrayList<>();
      if (cbFootball.isChecked()) liveTypes.add("足球");
      if (cbBasketball.isChecked()) liveTypes.add("篮球");
      if (cbEsports.isChecked()) liveTypes.add("电竞");
      if (cbOther.isChecked()) liveTypes.add("其他");
      
      if (liveTypes.isEmpty()) {
            Toast.makeText(this, "请至少选择一项直播赛事", Toast.LENGTH_SHORT).show();
            return;
      }
      
      // 收集其他信息
      String experience = spExperience.getSelectedItem().toString();
      String qq = etQQ.getText().toString().trim();
      String wechat = etWechat.getText().toString().trim();
      String phone = etPhone.getText().toString().trim();
      String inviter = etInviter.getText().toString().trim();
      String inviterPhone = etInviterPhone.getText().toString().trim();
      
      // 提交到服务器
      submitToServer(liveTypes, experience, realName, idCard, idCardPhotoUrl,
                qq, wechat, phone, introduction, inviter, inviterPhone, captcha);
    }
   
    private boolean validateIdCard(String idCard) {
      // 简单的身份证验证
      return idCard.matches("(^\\d{15}$)|(^\\d{18}$)|(^\\d{17}(\\d|X|x)$");
    }
   
    private void submitToServer(List<String> liveTypes, String experience, String realName,
            String idCard, String idCardPhoto, String qq, String wechat, String phone,
            String introduction, String inviter, String inviterPhone, String captcha) {
      
      // 使用Retrofit或Volley提交数据
      // 显示加载中
      ProgressDialog progressDialog = new ProgressDialog(this);
      progressDialog.setMessage("提交中...");
      progressDialog.setCancelable(false);
      progressDialog.show();
      
      // 构造请求体
      JSONObject requestBody = new JSONObject();
      try {
            requestBody.put("liveType", new JSONArray(liveTypes));
            requestBody.put("experience", experience);
            requestBody.put("realName", realName);
            requestBody.put("idCard", idCard);
            requestBody.put("idCardPhoto", idCardPhoto);
            requestBody.put("qq", qq);
            requestBody.put("wechat", wechat);
            requestBody.put("phone", phone);
            requestBody.put("introduction", introduction);
            requestBody.put("inviter", inviter);
            requestBody.put("inviterPhone", inviterPhone);
            requestBody.put("captcha", captcha);
            requestBody.put("agreed", true);
      } catch (JSONException e) {
            e.printStackTrace();
      }
      
      // 实际网络请求
      // 成功回调
      progressDialog.dismiss();
      Toast.makeText(this, "提交成功,请等待审核", Toast.LENGTH_SHORT).show();
      finish();
    }
}
4、iOS实现 (Objective-C)

// AnchorCertificationViewController.h
#import <UIKit/UIKit.h>

@interface AnchorCertificationViewController : UIViewController <UINavigationControllerDelegate, UIImagePickerControllerDelegate>

@end

// AnchorCertificationViewController.m
#import "AnchorCertificationViewController.h"

@interface AnchorCertificationViewController ()

@property (weak, nonatomic) IBOutlet UITextField *realNameField;
@property (weak, nonatomic) IBOutlet UITextField *idCardField;
@property (weak, nonatomic) IBOutlet UITextField *qqField;
@property (weak, nonatomic) IBOutlet UITextField *wechatField;
@property (weak, nonatomic) IBOutlet UITextField *phoneField;
@property (weak, nonatomic) IBOutlet UITextView *introductionView;
@property (weak, nonatomic) IBOutlet UITextField *inviterField;
@property (weak, nonatomic) IBOutlet UITextField *inviterPhoneField;
@property (weak, nonatomic) IBOutlet UITextField *captchaField;

@property (weak, nonatomic) IBOutlet UIButton *footballBtn;
@property (weak, nonatomic) IBOutlet UIButton *basketballBtn;
@property (weak, nonatomic) IBOutlet UIButton *esportsBtn;
@property (weak, nonatomic) IBOutlet UIButton *otherBtn;

@property (weak, nonatomic) IBOutlet UIPickerView *experiencePicker;
@property (weak, nonatomic) IBOutlet UIImageView *idCardImageView;
@property (weak, nonatomic) IBOutlet UIButton *getCaptchaBtn;
@property (weak, nonatomic) IBOutlet UIButton *submitBtn;
@property (weak, nonatomic) IBOutlet UIButton *agreeBtn;

@property (strong, nonatomic) NSArray *experienceOptions;
@property (strong, nonatomic) NSString *idCardPhotoUrl;
@property (assign, nonatomic) NSInteger countdown;
@property (strong, nonatomic) NSTimer *countdownTimer;

@end

@implementation AnchorCertificationViewController

- (void)viewDidLoad {
    ;
   
    ;
    ;
}

- (void)setupUI {
    self.introductionView.layer.borderWidth = 1.0;
    self.introductionView.layer.borderColor = .CGColor;
    self.introductionView.layer.cornerRadius = 5.0;
   
    self.idCardImageView.userInteractionEnabled = YES;
    UITapGestureRecognizer *tap = [ initWithTarget:self action:@selector(uploadIdCard)];
    ;
   
    self.experiencePicker.delegate = self;
    self.experiencePicker.dataSource = self;
}

- (void)setupData {
    self.experienceOptions = @[@"1个月", @"3个月", @"6个月", @"1年", @"2年", @"3年以上"];
    self.countdown = 60;
}

- (IBAction)liveTypeSelected:(UIButton *)sender {
    sender.selected = !sender.selected;
}

- (IBAction)getCaptchaTapped:(id)sender {
    NSString *phone = self.phoneField.text;
   
    if (phone.length == 0) {
      ;
      return;
    }
   
    // 简单的手机号验证
    NSString *phoneRegex = @"^1\\d{9}$";
    NSPredicate *phoneTest = ;
    if (!) {
      ;
      return;
    }
   
    ;
    ;
}

- (void)getCaptchaFromServer:(NSString *)phone {
    // 实际项目中这里应该调用API获取验证码
    ;
}

- (void)startCountdown {
    self.getCaptchaBtn.enabled = NO;
    self.countdownTimer = ;
}

- (void)updateCountdown {
    if (self.countdown > 0) {
       forState:UIControlStateDisabled];
      self.countdown--;
    } else {
      ;
      self.countdownTimer = nil;
      self.getCaptchaBtn.enabled = YES;
      ;
      self.countdown = 60;
    }
}

- (void)uploadIdCard {
    UIImagePickerController *picker = [ init];
    picker.delegate = self;
    picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
    picker.allowsEditing = YES;
    ;
}

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *)info {
    UIImage *image = info ?: info;
    self.idCardImageView.image = image;
   
    // 实际上传逻辑
    ;
   
    ;
}

- (void)uploadImageToServer:(UIImage *)image {
    // 这里实现实际上传逻辑,使用AFNetworking或其他网络库
    // 上传成功后保存返回的URL到self.idCardPhotoUrl
}

- (IBAction)submitTapped:(id)sender {
    NSString *realName = self.realNameField.text;
    NSString *idCard = self.idCardField.text;
    NSString *introduction = self.introductionView.text;
    NSString *captcha = self.captchaField.text;
   
    // 验证必填项
    if (realName.length == 0) {
      ;
      return;
    }
   
    if (idCard.length == 0 || !) {
      ;
      return;
    }
   
    if (self.idCardPhotoUrl.length == 0) {
      ;
      return;
    }
   
    if (introduction.length < 15) {
      ;
      return;
    }
   
    if (captcha.length == 0) {
      ;
      return;
    }
   
    if (!self.agreeBtn.selected) {
      ;
      return;
    }
   
    // 收集直播类型
    NSMutableArray *liveTypes = ;
    if (self.footballBtn.selected) ;
    if (self.basketballBtn.selected) ;
    if (self.esportsBtn.selected) ;
    if (self.otherBtn.selected) ;
   
    if (liveTypes.count == 0) {
      ;
      return;
    }
   
    // 收集其他信息
    NSInteger selectedRow = ;
    NSString *experience = self.experienceOptions;
    NSString *qq = self.qqField.text;
    NSString *wechat = self.wechatField.text;
    NSString *phone = self.phoneField.text;
    NSString *inviter = self.inviterField.text;
    NSString *inviterPhone = self.inviterPhoneField.text;
   
    // 提交到服务器
    [self submitToServerWithLiveTypes:liveTypes experience:experience realName:realName
                           idCard:idCard idCardPhoto:self.idCardPhotoUrl qq:qq
                           wechat:wechat phone:phone introduction:introduction
                        inviter:inviter inviterPhone:inviterPhone captcha:captcha];
}

- (BOOL)validateIdCard:(NSString *)idCard {
    NSString *regex = @"(^\\d{15}$)|(^\\d{18}$)|(^\\d{17}(\\d|X|x)$";
    NSPredicate *predicate = ;
    return ;
}

- (void)submitToServerWithLiveTypes:(NSArray *)liveTypes experience:(NSString *)experience
                        realName:(NSString *)realName idCard:(NSString *)idCard
                      idCardPhoto:(NSString *)idCardPhoto qq:(NSString *)qq
                        wechat:(NSString *)wechat phone:(NSString *)phone
                     introduction:(NSString *)introduction inviter:(NSString *)inviter
                  inviterPhone:(NSString *)inviterPhone captcha:(NSString *)captcha {
   
    // 显示加载中
    UIAlertController *loadingAlert = ;
    ;
   
    // 构造请求参数
    NSDictionary *params = @{
      @"liveType": liveTypes,
      @"experience": experience,
      @"realName": realName,
      @"idCard": idCard,
      @"idCardPhoto": idCardPhoto,
      @"qq": qq ?: @"",
      @"wechat": wechat ?: @"",
      @"phone": phone ?: @"",
      @"introduction": introduction,
      @"inviter": inviter ?: @"",
      @"inviterPhone": inviterPhone ?: @"",
      @"captcha": captcha,
      @"agreed": @YES
    };
   
    // 实际网络请求
    // 使用AFNetworking或NSURLSession
    // 成功回调
    [loadingAlert dismissViewControllerAnimated:YES completion:^{
      ;
      
5、数据库设计 (MySQL)

CREATE TABLE `anchor_certification` (
`id` INT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL COMMENT '主播真实姓名',
`identity_card` VARCHAR(18) NOT NULL COMMENT '身份证号码',
`identity_photo_front` VARCHAR(255) NOT NULL COMMENT '身份证正面照片路径',
`identity_photo_back` VARCHAR(255) NOT NULL COMMENT '身份证反面照片路径',
`identity_photo_handheld` VARCHAR(255) NOT NULL COMMENT '手持身份证照片路径',
`contact_type` ENUM('QQ', '微信', '电话') DEFAULT NULL COMMENT '联系方式类型',
`contact_value` VARCHAR(50) DEFAULT NULL COMMENT '联系方式内容',
`live_experience` ENUM('1个月', '3个月', '1年', '3年', '5年以上') NOT NULL COMMENT '直播经验',
`live_type` SET('足球', '篮球', '电竞', '娱乐', '其他') NOT NULL COMMENT '擅长的直播类型',
`personal_intro` TEXT NOT NULL COMMENT '个人简介',
`invite_code` VARCHAR(20) DEFAULT NULL COMMENT '邀请人邀请码',
`status` ENUM('待审核', '已通过', '已拒绝') DEFAULT '待审核' COMMENT '审核状态',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='主播认证信息表';

https://i-blog.csdnimg.cn/direct/757ec430bdfe45a4aaf51294e0401462.png#pic_center

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 开发体育赛事直播体系主播认证功能技术实现方案