1. プロジェクト設定
manifest.json の設定
json
{
"mp-weixin": {
"appid": "あなたの小程序AppID",
"setting": {
"urlCheck": false
},
"usingComponents": true,
"permission": {
"scope.userLocation": {
"desc": "近くのサービスを表示するために位置情報を取得します"
}
},
"requiredPrivateInfos": [
"getPhoneNumber"
]
}
}
2. ユーザープロフィールの取得
ヘッダーとニックネームの取得 (ユーザー操作によるトリガー)
vue
<template>
<view class="profile-container">
<!-- ヘッダー画像の選択 -->
<button class="header-btn" open-type="chooseAvatar" @chooseavatar="onSelectAvatar">
<image class="header" :src="profile.avatar" mode="aspectFill"></image>
</button>
<!-- ニックネーム入力 -->
<input
class="nickname-field"
type="text"
v-model="profile.nickName"
placeholder="ニックネームを入力してください"
@blur="onNickNameChange"
/>
<view class="profile-status">
<text>ヘッダー: {{ profile.avatar ? '設定済み' : '未設定' }}</text>
<text>ニックネーム: {{ profile.nickName || '未設定' }}</text>
</view>
</view>
</template>
<script>
export default {
data() {
return {
profile: {
avatar: '',
nickName: ''
}
};
},
methods: {
// アバター選択時の処理
onSelectAvatar(e) {
this.profile.avatar = e.detail.avatarUrl;
this.uploadProfileImage(e.detail.avatarUrl);
},
// ニックネーム変更時の処理
onNickNameChange(e) {
this.profile.nickName = e.detail.value;
},
// サーバーへのプロフィール画像アップロード
async uploadProfileImage(filePath) {
try {
const uploadTask = uni.uploadFile({
url: 'あなたのサーバーアドレス',
filePath: filePath,
name: 'profileImage',
formData: { type: 'header' },
success: res => console.log('アップロード成功:', res),
fail: err => console.error('アップロード失敗:', err)
});
} catch (error) {
console.error('画像アップロードエラー:', error);
}
}
}
};
</script>
<style>
.profile-container {
padding: 30rpx;
}
.header-btn {
width: 120rpx;
height: 120rpx;
border-radius: 50%;
overflow: hidden;
padding: 0;
margin: 40rpx auto;
}
.header {
width: 100%;
height: 100%;
border-radius: 50%;
}
.nickname-field {
height: 80rpx;
border: 1px solid #ddd;
border-radius: 10rpx;
padding: 0 20rpx;
margin: 30rpx 0;
}
.profile-status {
margin-top: 40rpx;
}
.profile-status text {
display: block;
margin: 10rpx 0;
font-size: 28rpx;
}
</style>
3. ログイン機能の実装
vue
<template>
<view class="auth-container">
<!-- ログインボタン -->
<button
v-if="!isLoggedIn"
type="primary"
open-type="getUserInfo"
@getuserinfo="handleUserInfo"
@click="initiateLogin"
>
微信でログイン
</button>
<!-- ユーザー情報の表示 -->
<view v-else class="user-profile">
<image class="user-header" :src="user.avatar" mode="aspectFill"></image>
<text class="user-name">{{ user.nickName }}</text>
<button @click="signOut" class="logout">ログアウト</button>
</view>
<!-- ログインステータス -->
<view class="auth-state">
<text>ログイン状態: {{ isLoggedIn ? 'ログイン中' : '未ログイン' }}</text>
</view>
</view>
</template>
<script>
export default {
data() {
return {
isLoggedIn: false,
user: {
avatar: '',
nickName: '',
id: ''
},
authCode: ''
};
},
onLoad() {
this.verifyLoginStatus();
},
methods: {
verifyLoginStatus() {
const token = uni.getStorageSync('authToken');
const userData = uni.getStorageSync('userDetails');
if (token && userData) {
this.isLoggedIn = true;
this.user = userData;
}
},
initiateLogin() {
this.fetchAuthCode();
},
fetchAuthCode() {
uni.login({
provider: 'weixin',
success: loginRes => {
this.authCode = loginRes.code;
},
fail: err => {
console.error('コード取得失敗:', err);
uni.showToast({ title: 'ログインに失敗しました', icon: 'none' });
}
});
},
async handleUserInfo(e) {
if (e.detail.userInfo) {
this.user = {
avatar: e.detail.userInfo.avatarUrl,
nickName: e.detail.userInfo.nickName
};
try {
const loginResponse = await this.performLogin({
code: this.authCode,
userInfo: this.user
});
if (loginResponse.success) {
this.isLoggedIn = true;
uni.setStorageSync('authToken', loginResponse.token);
uni.setStorageSync('userDetails', this.user);
uni.showToast({ title: 'ログイン成功', icon: 'success' });
}
} catch (error) {
console.error('ログインエラー:', error);
uni.showToast({ title: 'ログインに失敗しました', icon: 'none' });
}
} else {
uni.showToast({ title: '承認が拒否されました', icon: 'none' });
}
},
performLogin(loginData) {
return new Promise((resolve, reject) => {
uni.request({
url: 'あなたのAPIエンドポイント',
method: 'POST',
data: loginData,
success: res => {
if (res.data.code === 200) {
resolve({ success: true, token: res.data.data.token });
} else {
reject(res.data.message);
}
},
fail: err => {
reject(err);
}
});
});
},
signOut() {
this.isLoggedIn = false;
this.user = { avatar: '', nickName: '', id: '' };
uni.removeStorageSync('authToken');
uni.removeStorageSync('userDetails');
uni.showToast({ title: 'ログアウトしました', icon: 'success' });
}
}
};
</script>
4. 電話番号の取得
vue
<template>
<view class="phone-section">
<view class="phone-display">
<text>電話番号: {{ phone || '未登録' }}</text>
</view>
<!-- 電話番号取得ボタン -->
<button
v-if="!phone"
open-type="getPhoneNumber"
@getphonenumber="fetchPhoneNumber"
type="primary"
>
電話番号を登録
</button>
<button v-else @click="removePhone" class="unbind">
電話番号を解除
</button>
</view>
</template>
<script>
export default {
data() {
return {
phone: ''
};
},
onLoad() {
this.checkPhoneBinding();
},
methods: {
checkPhoneBinding() {
const storedPhone = uni.getStorageSync('userPhone');
if (storedPhone) {
this.phone = storedPhone;
}
},
async fetchPhoneNumber(e) {
if (e.detail.errMsg === 'getPhoneNumber:ok') {
try {
const encryptedData = e.detail.encryptedData;
const iv = e.detail.iv;
const loginRes = await new Promise(resolve => {
uni.login({ provider: 'weixin', success: resolve });
});
const decryptResult = await this.decryptPhone({
code: loginRes.code,
encryptedData,
iv
});
if (decryptResult.success) {
this.phone = decryptResult.phoneNumber;
uni.setStorageSync('userPhone', this.phone);
uni.showToast({ title: '登録完了', icon: 'success' });
}
} catch (error) {
console.error('電話番号取得エラー:', error);
uni.showToast({ title: '電話番号取得に失敗しました', icon: 'none' });
}
} else {
uni.showToast({ title: '電話番号取得に失敗しました', icon: 'none' });
}
},
decryptPhone(phoneData) {
return new Promise((resolve, reject) => {
uni.request({
url: 'あなたのデコードAPIエンドポイント',
method: 'POST',
data: phoneData,
success: res => {
if (res.data.code === 200) {
resolve({ success: true, phoneNumber: res.data.data.phoneNumber });
} else {
reject(res.data.message);
}
},
fail: err => {
reject(err);
}
});
});
},
removePhone() {
uni.showModal({
title: '確認',
content: '電話番号を解除しますか?',
success: res => {
if (res.confirm) {
this.phone = '';
uni.removeStorageSync('userPhone');
uni.showToast({ title: '解除完了', icon: 'success' });
}
}
});
}
}
};
</script>