index.vue 8.76 KB
<template>
    <view class="min-h-screen bg-gray-50 p-5 pb-24">
        <!-- Avatar -->
        <view class="flex flex-col items-center py-8" @click="changeAvatar">
            <view class="w-24 h-24 rounded-full bg-gray-100 flex items-center justify-center mb-2 overflow-hidden">
                <image :src="formData.avatar_url || defaultAvatar" class="w-full h-full" mode="aspectFit" />
            </view>
            <text class="text-gray-500 text-sm">上传头像</text>
        </view>

        <!-- Form -->
        <view class="space-y-6">
            <!-- Nickname -->
            <view class="mb-6">
                <label class="block text-sm font-medium text-gray-700 mb-2">昵称</label>
                <view class="bg-white rounded-xl p-2 border border-gray-200">
                    <nut-input
                        v-model="formData.nickname"
                        placeholder="请输入昵称"
                        :border="false"
                        class="!bg-transparent !border-none !p-0 text-base"
                    />
                </view>
            </view>

            <!-- birth_date -->
            <view class="mb-6">
                <label class="block text-sm font-medium text-gray-700 mb-2">出生年月</label>
                <view class="bg-white rounded-xl p-4 border border-gray-200" @click="showDatePicker = true">
                    <view class="flex justify-between items-center">
                        <text :class="{'text-gray-400': !formData.birth_date, 'text-gray-900': formData.birth_date}" class="text-base">
                            {{ formData.birth_date || '-/-/-/' }}
                        </text>
                        <DateIcon size="20" color="#888" />
                    </view>
                </view>
            </view>

            <!-- wheelchair_needed -->
            <view class="mb-6">
                <label class="block text-sm font-medium text-gray-700 mb-2">是否需要轮椅出行</label>
                <view class="bg-white rounded-xl p-4 border border-gray-200" @click="showWheelchairPicker = true">
                    <view class="flex justify-between items-center">
                        <text :class="{'text-gray-400': !formData.wheelchair_text, 'text-gray-900': formData.wheelchair_text}" class="text-base">
                            {{ formData.wheelchair_text || '请选择' }}
                        </text>
                        <Right size="16" color="#888" />
                    </view>
                </view>
            </view>
        </view>

        <!-- Save Button -->
        <view class="fixed bottom-0 left-0 right-0 p-4 bg-white border-t border-gray-100">
            <nut-button type="primary" size="large" color="#4A90E2" block @click="handleSave">保存</nut-button>
        </view>

        <!-- Popups -->
        <nut-popup v-model:visible="showDatePicker" position="bottom">
            <nut-date-picker
                v-model="currentDate"
                @confirm="onDateConfirm"
                @cancel="showDatePicker = false"
                :min-date="minDate"
                :max-date="maxDate"
                title="选择出生年月"
            ></nut-date-picker>
        </nut-popup>

        <nut-popup v-model:visible="showWheelchairPicker" position="bottom">
            <nut-picker
                v-model="wheelchairValue"
                :columns="wheelchairColumns"
                @confirm="onWheelchairConfirm"
                @cancel="showWheelchairPicker = false"
                title="是否需要轮椅出行"
            ></nut-picker>
        </nut-popup>

        <nut-image-preview v-model:show="previewVisible" :images="previewImages" />
    </view>
</template>

<script setup>
import { ref, reactive, onMounted } from 'vue';
import Taro from '@tarojs/taro';
import { My, Date as DateIcon, Right } from '@nutui/icons-vue-taro';
import BASE_URL from '@/utils/config';
// 默认头像
const defaultAvatar = 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg'
// 获取接口信息
import { getUserProfileAPI, updateUserProfileAPI } from '@/api/user';

/**
 * @description 表单数据
 */
const formData = reactive({
  avatar_url: '',
  nickname: '',
  birth_date: '',
  wheelchair_needed: null, // 0 for No, 1 for Yes
  wheelchair_text: '',
});

// --- Date Picker ---
/**
 * @description 控制日期选择器显示
 */
const showDatePicker = ref(false);
/**
 * @description 最小可选日期
 */
const minDate = new Date(1920, 0, 1);
/**
 * @description 最大可选日期
 */
const maxDate = new Date();
/**
 * @description 当前选中的日期
 */
const currentDate = ref(new Date());

/**
 * @description 确认选择日期
 * @param {object} param0 - 包含 selectedValue 的对象
 */
const onDateConfirm = ({ selectedValue }) => {
  formData.birth_date = selectedValue.join('-');
  showDatePicker.value = false;
};

// --- wheelchair_needed Picker ---
/**
 * @description 控制轮椅选择器显示
 */
const showWheelchairPicker = ref(false);
/**
 * @description 当前选中的轮椅选项
 */
const wheelchairValue = ref([]);
/**
 * @description 轮椅选择器选项
 */
const wheelchairColumns = ref([
  { text: '是', value: true },
  { text: '否', value: false },
]);

/**
 * @description 确认选择轮椅选项
 * @param {object} param0 - 包含 selectedValue 和 selectedOptions 的对象
 */
const onWheelchairConfirm = ({ selectedValue, selectedOptions }) => {
  formData.wheelchair_needed = selectedValue[0];
  formData.wheelchair_text = selectedOptions.map((option) => option.text).join('');
  showWheelchairPicker.value = false;
};

// --- Avatar ---
/**
 * @description 控制图片预览显示
 */
const previewVisible = ref(false);
/**
 * @description 预览的图片列表
 */
const previewImages = ref([]);

/**
 * @description 更换头像
 */
const changeAvatar = () => {
  Taro.chooseImage({
    count: 1,
    sizeType: ['compressed'],
    sourceType: ['album', 'camera'],
    success: (res) => {
      const tempFile = res.tempFiles[0];
      if (tempFile.size > 5 * 1024 * 1024) {
        Taro.showToast({
          title: '图片大小不能超过5MB',
          icon: 'none',
        });
        return;
      }

      Taro.showLoading({ title: '上传中...' });

      Taro.uploadFile({
        url: BASE_URL + '/admin/?m=srv&a=upload',
        filePath: tempFile.path,
        name: 'file',
        success: (uploadRes) => {
          Taro.hideLoading();
          const data = JSON.parse(uploadRes.data);
          if (data.code === 0) {
            formData.avatar_url = data.data.src;
            Taro.showToast({ title: '上传成功', icon: 'success' });
          } else {
            Taro.showToast({ title: data.msg || '上传失败', icon: 'none' });
          }
        },
        fail: () => {
          Taro.hideLoading();
          Taro.showToast({ title: '上传失败,请稍后重试', icon: 'none' });
        },
      });
    },
    fail: () => {
      Taro.showToast({ title: '选择图片失败', icon: 'none' });
    },
  });
};

// --- Save ---
/**
 * @description 验证表单数据
 * @returns {boolean} 验证是否通过
 */
const validateForm = () => {
  if (!formData.nickname.trim()) {
    Taro.showToast({
      title: '请输入昵称',
      icon: 'none'
    });
    return false;
  }

  if (!formData.birth_date) {
    Taro.showToast({
      title: '请选择出生年月',
      icon: 'none'
    });
    return false;
  }

  if (formData.wheelchair_needed === null || formData.wheelchair_needed === undefined) {
    Taro.showToast({
      title: '请选择是否需要轮椅出行',
      icon: 'none'
    });
    return false;
  }

  return true;
};

/**
 * @description 保存用户信息
 */
const handleSave = async () => {
  // 验证表单
  if (!validateForm()) {
    return;
  }

  // 如果头像为空,使用默认头像
  if (!formData.avatar_url) {
    formData.avatar_url = defaultAvatar;
  }

  // 保存数据
  const { code, data } = await updateUserProfileAPI(formData);
  if (code) {
    Taro.showToast({
      title: '保存成功',
      icon: 'success',
    });
    setTimeout(() => {
      Taro.navigateBack();
    }, 1500);
  }
};

/**
 * @description 页面加载时获取初始数据
 */
onMounted(async () => {
  // 获取用户信息
  const { code, data } = await getUserProfileAPI();
  if (code && data?.user) {
    Object.assign(formData, data.user);
    // 初始化勾选数据
    if (formData.birth_date) {
      currentDate.value = new Date(formData.birth_date);
    }
    // 设置轮椅选择器的值和显示文本
    if (formData.wheelchair_needed !== null && formData.wheelchair_needed !== undefined) {
      wheelchairValue.value = [formData.wheelchair_needed];
      formData.wheelchair_text = formData.wheelchair_needed ? '是' : '否';
    }
  }
});
</script>

<style>
.nut-input.mt-2 {
    padding: 12px 0 !important;
    border-bottom: 1px solid #e5e7eb;
}
</style>