longz
2026-04-27 25df88d0ab9d7444ed1d162b9efa1259ac2f6f66
frontend-admin/src/views/UsersView.vue
@@ -101,8 +101,22 @@
        <el-form-item label="手机">
          <el-input v-model="createForm.mobile" />
        </el-form-item>
        <el-form-item label="头像URL">
          <el-input v-model="createForm.avatarUrl" placeholder="可选" />
        <el-form-item label="头像">
          <div class="avatar-upload-row">
            <el-avatar v-if="createForm.avatarUrl" :size="64" :src="createForm.avatarUrl" />
            <el-avatar v-else :size="64">{{ (createForm.realName || createForm.username || "?").slice(0, 1) }}</el-avatar>
            <div class="avatar-upload-actions">
              <el-upload
                :show-file-list="false"
                accept=".jpg,.jpeg,.png,.webp,.gif"
                :http-request="(opt) => uploadAvatar(opt, 'create')"
              >
                <el-button :loading="avatarUploading === 'create'">上传头像</el-button>
              </el-upload>
              <el-button v-if="createForm.avatarUrl" link type="danger" @click="createForm.avatarUrl = ''">清除</el-button>
              <div class="avatar-upload-tip">支持 jpg、png、webp、gif,大小不超过 5MB</div>
            </div>
          </div>
        </el-form-item>
        <el-form-item label="角色" required>
          <el-select v-model="createForm.roleIds" multiple placeholder="必选,可多选" style="width: 100%">
@@ -133,8 +147,22 @@
        <el-form-item label="手机">
          <el-input v-model="editForm.mobile" />
        </el-form-item>
        <el-form-item label="头像URL">
          <el-input v-model="editForm.avatarUrl" />
        <el-form-item label="头像">
          <div class="avatar-upload-row">
            <el-avatar v-if="editForm.avatarUrl" :size="64" :src="editForm.avatarUrl" />
            <el-avatar v-else :size="64">{{ (editForm.realName || editForm.username || "?").slice(0, 1) }}</el-avatar>
            <div class="avatar-upload-actions">
              <el-upload
                :show-file-list="false"
                accept=".jpg,.jpeg,.png,.webp,.gif"
                :http-request="(opt) => uploadAvatar(opt, 'edit')"
              >
                <el-button :loading="avatarUploading === 'edit'">上传头像</el-button>
              </el-upload>
              <el-button v-if="editForm.avatarUrl" link type="danger" @click="editForm.avatarUrl = ''">清除</el-button>
              <div class="avatar-upload-tip">支持 jpg、png、webp、gif,大小不超过 5MB</div>
            </div>
          </div>
        </el-form-item>
        <el-form-item label="角色" required>
          <el-select v-model="editForm.roleIds" multiple placeholder="必选" style="width: 100%">
@@ -174,6 +202,7 @@
<script setup lang="ts">
import { onMounted, reactive, ref } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import type { UploadRequestOptions } from "element-plus";
import http from "../api/http";
type RoleRow = { id: number; roleCode: string; roleName: string };
@@ -191,6 +220,7 @@
const loading = ref(false);
const saving = ref(false);
const avatarUploading = ref<"create" | "edit" | "">("");
const rows = ref<UserRow[]>([]);
const page = ref(1);
const size = ref(10);
@@ -377,6 +407,31 @@
  }
}
async function uploadAvatar(opt: UploadRequestOptions, target: "create" | "edit") {
  const fd = new FormData();
  fd.append("file", opt.file as File);
  avatarUploading.value = target;
  try {
    const { data } = await http.post("/common/upload/image", fd, {
      headers: { "Content-Type": "multipart/form-data" },
    });
    const url = String(data.result?.url || "");
    if (!url) {
      throw new Error("上传结果缺少图片地址");
    }
    if (target === "create") {
      createForm.avatarUrl = url;
    } else {
      editForm.avatarUrl = url;
    }
    ElMessage.success("头像上传成功");
  } catch (e: unknown) {
    ElMessage.error(e instanceof Error ? e.message : "头像上传失败");
  } finally {
    avatarUploading.value = "";
  }
}
function openResetPwd(row: UserRow) {
  pwdUserId.value = row.id;
  pwdUserUuid.value = row.uuid;
@@ -489,4 +544,23 @@
  margin-top: 12px;
  justify-content: flex-end;
}
.avatar-upload-row {
  display: flex;
  align-items: center;
  gap: 14px;
}
.avatar-upload-actions {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
}
.avatar-upload-tip {
  color: #8a97b3;
  font-size: 12px;
  line-height: 1.4;
}
</style>