zjk
2026-03-10 07e2615c51198d14d4b608d2914fb805aac99a4b
feat: banner和运维人员上传
5个文件已修改
86 ■■■■■ 已修改文件
src/service/api/common.ts 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/upload.ts 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/operations/personnel/personnelManagement/components/PersonnelFormModal.vue 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/operations/personnel/personnelManagement/index.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/userContent/banner/components/BannerFormModal.vue 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/service/api/common.ts
@@ -13,9 +13,9 @@
/**
 * 通用文件上传
 * @param formData
 * @returns
 * @param formData
 * @returns
 */
export function uploadFile(formData: FormData) {
  return request.Post<Service.ResponseResult<{ id: string, name: string, url: string }>>('/vehicleConvoy/api/v1/common/uploadFile', formData)
  return request.Post<Service.ResponseResult<{ id: string, name: string, url: string }>>('/operation/base/v1/oss/upload', formData)
}
src/utils/upload.ts
@@ -33,34 +33,33 @@
    await new Promise(resolve => setTimeout(resolve, 600))
    // TODO: 等待具体上传接口出来后,取消注释以下真实 API 调用逻辑
    /*
    const formData = new FormData()
    if (file.file) {
      formData.append('file', file.file)
    }
    const { data, error } = await uploadFile(formData)
    if (data && !error) {
      file.url = data.url
      file.id = data.id
    const res = await uploadFile(formData)
    if (res.code === 200) {
      file.url = res.data.url
      file.id = res.data.id
      file.status = 'finished'
      onFinish()
    } else {
      onError()
      window.$message.error('文件上传失败')
    }
    */
   console.log('模拟返回逻辑开始')
    // --- 模拟返回逻辑开始 ---
    // 生成一个模拟的 URL (如果是图片则使用 base64 预览)
    file.url = 'https://haitunyingyu.obs.cn-southwest-2.myhuaweicloud.com/admin/8bbba1ccafda4456bf7e3b2054d78541.jpg' // 默认占位图
    const newId = `mock_${Date.now()}`
    file.status = 'finished'
    onFinish()
    // file.url = 'https://haitunyingyu.obs.cn-southwest-2.myhuaweicloud.com/admin/8bbba1ccafda4456bf7e3b2054d78541.jpg' // 默认占位图
    // const newId = `mock_${Date.now()}`
    // file.status = 'finished'
    // onFinish()
    // 关键修复:返回上传后的文件信息,供组件内使用
    return {
      id: newId,
      id: file.id,
      url: file.url,
      name: file.name,
      status: 'finished',
@@ -76,7 +75,7 @@
/**
 * 文件上传前校验封装
 * @param data
 * @param data
 * @param options 校验配置
 */
export function beforeUploadCheck(
src/views/operations/personnel/personnelManagement/components/PersonnelFormModal.vue
@@ -1,6 +1,7 @@
<script setup lang="ts">
import { ref, computed } from 'vue'
import type { FormInst, FormRules, UploadFileInfo } from 'naive-ui'
import type { FormInst, FormRules, UploadFileInfo , UploadCustomRequestOptions} from 'naive-ui'
import { customUploadRequest } from '@/utils/upload'
interface FormModel {
  nickName: string
@@ -136,11 +137,33 @@
  fileList.value = []
}
const handleUploadChange = (options: { fileList: UploadFileInfo[] }) => {
  fileList.value = options.fileList
  if (options.fileList.length > 0) {
    formModel.value.avatar = options.fileList[0].url || ''
const handleCustomUpload = async (options: UploadCustomRequestOptions) => {
  const result = await customUploadRequest(options as any)
  console.log('上传结果', result)
  if (result) {
    // 构建 JSON 数组字符串
    const pictureData = {
      id: result.id,
      name: result.name,
      url: result.url
    }
    formModel.value.avatar = JSON.stringify(pictureData)
    fileList.value = [{
      id: result.id,
      name: result.name,
      status: 'finished',
      url: result.url
    }]
    // 触发校验
    formRef.value?.validate(errors => {
      if (!errors) return
    }, (rule) => rule?.key === 'bannerPictures')
  }
}
const handleRemove = () => {
  formModel.value.avatar = ''
  fileList.value = []
}
</script>
@@ -176,10 +199,11 @@
      <div class="grid grid-cols-2 gap-4 items-start">
        <n-form-item label="头像" path="avatar">
          <n-upload
            v-model:file-list="fileList"
            :max="1"
            list-type="image-card"
            :file-list="fileList"
            @change="handleUploadChange"
            :custom-request="handleCustomUpload"
            @remove="handleRemove"
          >
            <div class="flex flex-col items-center justify-center" style="width: 100px; height: 100px">
              <span style="font-size: 32px; color: #ccc">+</span>
src/views/operations/personnel/personnelManagement/index.vue
@@ -241,7 +241,7 @@
    resizable: true,
    render: (row) => (
      <div class="flex items-center gap-2">
        {row.avatar && <img src={row.avatar} alt="头像" class="w-8 h-8 rounded-full" />}
        {row.avatar && <img src={JSON.parse(row.avatar).url} alt="头像" class="w-8 h-8 rounded-full" />}
        {!row.avatar && <div class="w-8 h-8 rounded-full bg-gray-300 flex items-center justify-center text-sm">头</div>}
        <span>{row.nickName}</span>
      </div>
src/views/userContent/banner/components/BannerFormModal.vue
@@ -112,6 +112,7 @@
const handleCustomUpload = async (options: UploadCustomRequestOptions) => {
  const result = await customUploadRequest(options as any)
  console.log('上传结果', result)
  if (result) {
    // 构建 JSON 数组字符串
    const pictureData = [{
@@ -120,6 +121,12 @@
      url: result.url
    }]
    formModel.value.bannerPictures = JSON.stringify(pictureData)
    fileList.value = [{
      id: result.id,
      name: result.name,
      status: 'finished',
      url: result.url
    }]
    // 触发校验
    formRef.value?.validate(errors => {
      if (!errors) return
@@ -139,7 +146,7 @@
const handleConfirm = async () => {
  try {
    await formRef.value?.validate()
    const params = {
      ...formModel.value,
      bannerStatus: formModel.value.bannerStatus ? 1 : 2,
@@ -177,7 +184,7 @@
    if (props.mode !== 'add' && props.rowData) {
      // 编辑/查看模式,回显数据
      const row = props.rowData
      // 解析图片
      try {
        const pictures = JSON.parse(row.bannerPictures || '[]')
@@ -241,9 +248,9 @@
      action: true
    }"
    :content-style="{
      padding: '16px 24px 0px 24px',
      maxHeight: '60vh',
      overflow: 'auto'
      // padding: '16px 24px 0px 24px',
      // maxHeight: '60vh',
      // overflow: 'auto'
    }"
    @close="handleClose"
  >