gaoluyang
2026-06-24 bfdc0e0e6d5e47aa501f9b6fadd143d9c97cf00a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
<script lang="ts" setup>
import type { FormInstance, UploadProps } from 'ant-design-vue';
 
import type { UploadData } from './upload';
 
import { inject, reactive, ref } from 'vue';
 
import { IconifyIcon } from '../../../../packages/icons/src';
 
import {
  Button,
  Divider,
  Form,
  Input,
  message,
  Modal,
  Upload,
} from 'ant-design-vue';
 
import { beforeVideoUpload, HEADERS, UPLOAD_URL, UploadType } from './upload';
 
withDefaults(
  defineProps<{
    open?: boolean;
  }>(),
  {
    open: false,
  },
);
 
const emit = defineEmits<{
  'update:open': [v: boolean];
  uploaded: [v: void];
}>();
 
const accountId = inject<number>('accountId');
 
const uploadRules = {
  introduction: [
    { message: '请输入描述', required: true, trigger: 'blur' } as const,
  ],
  title: [{ message: '请输入标题', required: true, trigger: 'blur' } as const],
};
 
function handleCancel() {
  emit('update:open', false);
}
 
const fileList = ref<any[]>([]);
 
const uploadData: UploadData = reactive({
  accountId: accountId!,
  introduction: '',
  title: '',
  type: UploadType.Video,
});
 
const uploadFormRef = ref<FormInstance | null>(null);
const uploadVideoRef = ref<any>(null);
 
async function submitVideo() {
  await uploadFormRef.value?.validate();
  uploadVideoRef.value?.submit();
}
 
/** 自定义上传 */
const customRequest: UploadProps['customRequest'] = async function (options) {
  const { file, onError, onSuccess } = options;
 
  const formData = new FormData();
  formData.append('file', file as File);
  formData.append('type', uploadData.type);
  formData.append('title', uploadData.title);
  formData.append('introduction', uploadData.introduction);
  formData.append('accountId', String(uploadData.accountId));
 
  try {
    const response = await fetch(UPLOAD_URL, {
      body: formData,
      headers: HEADERS,
      method: 'POST',
    });
 
    const res = await response.json();
 
    if (res.code !== 0) {
      message.error(`上传出错:${res.msg}`);
      onError?.(new Error(res.msg));
      return;
    }
 
    // 清空上传时的各种数据
    fileList.value = [];
    uploadData.title = '';
    uploadData.introduction = '';
 
    emit('update:open', false);
    message.success('上传成功');
    onSuccess?.(res);
    emit('uploaded');
  } catch (error: any) {
    message.error(`上传失败: ${error.message}`);
    onError?.(error);
  }
};
</script>
 
<template>
  <Modal
    :open="open"
    title="新建视频"
    width="600px"
    @cancel="handleCancel"
    @ok="submitVideo"
  >
    <Upload
      ref="uploadVideoRef"
      :action="UPLOAD_URL"
      :auto-upload="false"
      :before-upload="beforeVideoUpload"
      :custom-request="customRequest"
      :file-list="fileList"
      :headers="HEADERS"
      :limit="1"
      :multiple="true"
      class="mb-4"
    >
      <Button type="primary">
        <IconifyIcon icon="lucide:video" class="mr-1" />
        选择视频
      </Button>
    </Upload>
    <div class="mb-4 ml-1 text-sm text-gray-500">
      格式支持 MP4,文件大小不超过 10MB
    </div>
 
    <Divider />
 
    <Form
      ref="uploadFormRef"
      :model="uploadData"
      :rules="uploadRules"
      layout="vertical"
    >
      <Form.Item label="标题" name="title">
        <Input
          v-model:value="uploadData.title"
          placeholder="标题将展示在相关播放页面,建议填写清晰、准确、生动的标题"
        />
      </Form.Item>
      <Form.Item label="描述" name="introduction">
        <Input.TextArea
          v-model:value="uploadData.introduction"
          :rows="3"
          placeholder="介绍语将展示在相关播放页面,建议填写简洁明确、有信息量的内容"
        />
      </Form.Item>
    </Form>
  </Modal>
</template>