# MatchProfileSet

A personal profile setting component that provides editing functionality for user avatar, nickname and other basic information, supporting avatar upload and nickname modification.

# Import

import PressMatchProfileSet from 'press-next/press-match-profile-set/press-match-profile-set.vue';

# Usage

# Basic Usage

<template>
  <PressMatchProfileSet
    desc="To facilitate content display on pages such as scores, authorize us to get your account nickname"
    :avatar-url="avatarUrl"
    :nickname="nickname"
    @avatar-click="handleAvatarClick"
    @nickname-change="handleNicknameChange"
    @account-click="handleAccountClick"
  />
</template>

<script setup>
import { ref } from 'vue';

const avatarUrl = ref('https://example.com/avatar.jpg');
const nickname = ref('User Nickname');

const handleAvatarClick = () => {
  console.log('Avatar clicked');
};

const handleNicknameChange = (value) => {
  console.log('Nickname changed:', value);
  nickname.value = value;
};

const handleAccountClick = () => {
  console.log('Switch account button clicked');
};
</script>

# Avatar Upload

The component supports avatar click upload functionality:

<template>
  <PressMatchProfileSet
    :avatar-url="avatarUrl"
    :nickname="nickname"
    @avatar-click="handleAvatarUpload"
  />
</template>

<script setup>
import { ref } from 'vue';

const avatarUrl = ref('');
const nickname = ref('Enter nickname');

const handleAvatarUpload = () => {
  // Call image picker
  uni.chooseImage({
    count: 1,
    sizeType: ['compressed'],
    sourceType: ['album', 'camera'],
    success: (res) => {
      avatarUrl.value = res.tempFilePaths[0];
      // Upload to server
      uploadAvatar(res.tempFilePaths[0]);
    }
  });
};

const uploadAvatar = (filePath) => {
  uni.uploadFile({
    url: 'https://api.example.com/upload',
    filePath,
    name: 'avatar',
    success: (uploadRes) => {
      const data = JSON.parse(uploadRes.data);
      avatarUrl.value = data.url;
    }
  });
};
</script>

# Nickname Editing

Supports real-time nickname editing and validation:

<template>
  <PressMatchProfileSet
    :avatar-url="avatarUrl"
    :nickname="nickname"
    nickname-placeholder="Please enter your nickname"
    @nickname-change="handleNicknameChange"
    @nickname-blur="handleNicknameBlur"
  />
</template>

<script setup>
import { ref } from 'vue';

const avatarUrl = ref('https://example.com/avatar.jpg');
const nickname = ref('');

const handleNicknameChange = (value) => {
  nickname.value = value;
};

const handleNicknameBlur = (value) => {
  // Nickname length validation
  if (value.length > 20) {
    uni.showToast({
      title: 'Nickname cannot exceed 20 characters',
      icon: 'none'
    });
    return;
  }
  
  // Sensitive word filtering
  if (containsSensitiveWords(value)) {
    uni.showToast({
      title: 'Nickname contains sensitive words',
      icon: 'none'
    });
    return;
  }
};

const containsSensitiveWords = (text) => {
  const sensitiveWords = ['badword1', 'badword2'];
  return sensitiveWords.some(word => text.includes(word));
};
</script>
<template>
  <PressMatchProfileSet
    :avatar-url="avatarUrl"
    :nickname="nickname"
    foot-button-text="Logout"
    @account-click="handleLogout"
  >
    <template #confirm-btn>
      <PressButton
        type="primary"
        block
        @click="handleCustomAction"
      >
        Custom Button
      </PressButton>
    </template>
  </PressMatchProfileSet>
</template>

<script setup>
import { ref } from 'vue';

const avatarUrl = ref('https://example.com/avatar.jpg');
const nickname = ref('User Nickname');

const handleLogout = () => {
  console.log('Logout');
};

const handleCustomAction = () => {
  console.log('Custom action');
};
</script>

# Complete Example

<template>
  <div class="profile-page">
    <PressMatchProfileSet
      desc="To facilitate content display on pages such as scores, authorize us to get your account nickname"
      :avatar-url="avatarUrl"
      :nickname="nickname"
      :default-avatar-url="defaultAvatar"
      nickname-placeholder="Please enter nickname"
      foot-button-text="Switch QQ Account"
      custom-class="custom-profile"
      @avatar-click="handleAvatarClick"
      @nickname-change="handleNicknameChange"
      @nickname-blur="handleNicknameBlur"
      @nickname-auth="handleNicknameAuth"
      @account-click="handleAccountClick"
    />
  </div>
</template>

<script setup>
import { ref } from 'vue';

const avatarUrl = ref('');
const nickname = ref('');
const defaultAvatar = 'https://example.com/default-avatar.png';

const handleAvatarClick = () => {
  uni.showActionSheet({
    itemList: ['Take Photo', 'Choose from Album'],
    success: (res) => {
      const sourceType = res.tapIndex === 0 ? ['camera'] : ['album'];
      
      uni.chooseImage({
        count: 1,
        sizeType: ['compressed'],
        sourceType,
        success: (chooseRes) => {
          uploadAvatar(chooseRes.tempFilePaths[0]);
        }
      });
    }
  });
};

const handleNicknameChange = (value) => {
  nickname.value = value;
};

const handleNicknameBlur = (value) => {
  if (!value.trim()) {
    uni.showToast({
      title: 'Please enter nickname',
      icon: 'none'
    });
    return;
  }
  
  if (value.length > 20) {
    uni.showToast({
      title: 'Nickname cannot exceed 20 characters',
      icon: 'none'
    });
    return;
  }
};

const handleNicknameAuth = () => {
  console.log('Trigger WeChat nickname authorization');
};

const handleAccountClick = () => {
  uni.showModal({
    title: 'Confirm',
    content: 'Are you sure you want to switch account?',
    success: (res) => {
      if (res.confirm) {
        // Execute account switching logic
        console.log('Switch account');
      }
    }
  });
};

const uploadAvatar = (filePath) => {
  uni.showLoading({ title: 'Uploading...' });
  
  uni.uploadFile({
    url: 'https://api.example.com/upload/avatar',
    filePath,
    name: 'avatar',
    success: (res) => {
      const data = JSON.parse(res.data);
      avatarUrl.value = data.url;
      uni.hideLoading();
    },
    fail: () => {
      uni.hideLoading();
      uni.showToast({
        title: 'Upload failed',
        icon: 'none'
      });
    }
  });
};
</script>

# API

# Props

Attribute Description Type Default
foot-button-text Footer button text string '切换QQ账号'
custom-class Custom style class name string ''
authorization-class Authorization item custom style class name string ''
desc Description text string ''
avatar-url Avatar URL string ''
nickname Nickname string ''
default-avatar-url Default avatar URL string ''
nickname-placeholder Nickname input placeholder string ''

# Events

Event Description Parameters
account-click Triggered when footer button is clicked -
avatar-click Triggered when avatar is clicked -
nickname-change Triggered when nickname input changes value: string
nickname-blur Triggered when nickname input loses focus value: string
nickname-auth Triggered when clicking the arrow on the right side of nickname, used to trigger WeChat nickname authorization -

# Slots

Name Description
confirm-btn Custom footer button

# Style Variables

The component provides the following CSS variables, which can be used to customize styles.

Name Default Value Description
--pmps-profile-foot-mt $spacing-xl Footer button top margin
--pmps-profile-padding-lr $spacing-lg Component left and right padding
--pmps-profile-foot-padding-lr $spacing-md Footer button left and right padding
--pmps-foot-height 1.08rem Footer button height
--pmps-profile-bg-color $color-surface-default Background color

# Custom Style Example

<template>
  <PressMatchProfileSet
    :avatar-url="avatarUrl"
    :nickname="nickname"
    class="custom-profile-set"
  />
</template>

<style>
.custom-profile-set {
  --pmps-profile-bg-color: #f8f9fa;
  --pmps-profile-padding-lr: 20px;
  --pmps-profile-foot-mt: 30px;
  --pmps-foot-height: 44px;
}
</style>

# Notes

  1. This component is mainly used for personal profile setting pages, providing avatar and nickname editing functionality
  2. Avatar display priority: avatar-url > default-avatar-url
  3. The component internally uses the PressMatchAuthorizationItem component to render authorization items
  4. The default footer button text is "切换QQ账号" (Switch QQ Account), which can be customized via foot-button-text
  5. Supports fully customizing the footer button through slots

# FAQ

# How to get WeChat Mini Program avatar?

const handleAvatarClick = () => {
  wx.chooseMedia({
    count: 1,
    mediaType: ['image'],
    sourceType: ['album', 'camera'],
    success: (res) => {
      avatarUrl.value = res.tempFiles[0].tempFilePath;
    }
  });
};

# How to validate nickname format?

const handleNicknameBlur = (value) => {
  if (value.length < 2) {
    wx.showToast({ title: 'Nickname must be at least 2 characters', icon: 'none' });
    return;
  }
  if (value.length > 20) {
    wx.showToast({ title: 'Nickname cannot exceed 20 characters', icon: 'none' });
    return;
  }
  // Other validation logic...
};

# How to upload avatar to server?

const uploadAvatar = (tempFilePath) => {
  wx.uploadFile({
    url: 'https://your-api.com/upload',
    filePath: tempFilePath,
    name: 'avatar',
    success: (res) => {
      const data = JSON.parse(res.data);
      avatarUrl.value = data.url;
    }
  });
};