Files
coursehomework-front/src/components/AttachmentUpload.vue
T
wanghu e6639f7925 feat(M5): P0 契约层 + 审批/应用设置下线
- types/homeworkV2.ts:V2 全量类型契约(五态/枚举/矩阵/版本/通知)
- teacherHomework/studentHomework/notification 三客户端(28 端点)
- §6 审批功能下线:删 ApprovalList/ApprovalSetting/ApprovalFlowEditor,
  types/api/menu/menuRoute/App/mock 同步清理,DROPPED_MOD_IDS={5,6}
- §7 应用设置下线:删 HomeworkSetting/TypeSetBox/UserCheckInput,
  SettingApi 与 dict/contacts 死代码清理,DROPPED_MOD_IDS 扩 {21}
- 新增 V2 组件:TeacherHomeworks(已发布+草稿箱)、ReviewModal(批阅弹窗)、
  AttachmentUpload(附件上传)——尚未挂路由,页面切换随后续阶段
2026-09-16 02:29:32 +08:00

130 lines
4.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<!-- V2 附件上传:emit AttachmentItem[](fileId/fileUrl/fileType/fileName/sort)。
fileUrl 统一存 /api/file/Preview?id=(浏览器可直接渲染;下载走 Down 直链)。 -->
<div class="attachment-upload">
<Upload
:on-success="onSuccess"
:on-remove="onRemove"
:default-file-list="fileList"
:action="uploadUrl"
:accept="accept"
:multiple="multiple"
:format="formatArr"
:max-size="204800"
:on-format-error="onFormatError"
:on-exceeded-size="onExceeded"
>
<Button><Icon type="ios-cloud-upload-outline"></Icon>{{ buttonText || (imageOnly ? "拍照/上传图片" : "选择文件") }}</Button>
</Upload>
<span class="upload-tip">大小不超过 200MB</span>
</div>
</template>
<script lang="ts">
import { Message } from "view-ui-plus";
import config from "@/assets/config/host.config";
import type { AttachmentItem } from "@/types/homeworkV2";
/** base/FileUpload(form-data: file)返回体:{code,msg,data:{fileid,name,fileurl,host,type,size}} */
interface FileUploadResp {
code: number;
msg?: string;
data: { fileid: number; name: string; fileurl: string; host: string; type: string; size: number };
}
export default {
name: "AttachmentUpload",
props: {
/** 已选附件(v-model) */
modelValue: { type: Array as () => AttachmentItem[], default: () => [] },
/** 仅图片(拍照提交场景) */
imageOnly: { type: Boolean, default: false },
multiple: { type: Boolean, default: true },
/** 留空时按 imageOnly 自动取「拍照/上传图片」或「选择文件」 */
buttonText: { type: String, default: "" },
},
emits: ["update:modelValue"],
data() {
return {
uploadUrl: (config.isMock ? "" : config.serviceHost) + "/api/file/Upload",
};
},
computed: {
accept(): string {
return this.imageOnly ? "image/*" : "";
},
formatArr(): string[] {
return this.imageOnly
? ["jpg", "jpeg", "gif", "png", "bmp", "webp"]
: ["jpg", "jpeg", "gif", "png", "bmp", "webp", "xls", "doc", "txt", "docx", "xlsx", "zip", "rar", "pdf", "ppt", "pptx", "wps", "mp3", "mp4"];
},
/** iview Upload 回显列表(只读 name;移除按项过滤) */
fileList(): any[] {
return (this.modelValue || []).filter((a) => a.fileName).map((a) => ({ name: a.fileName, url: this.previewUrl(a), _item: a }));
},
},
methods: {
previewUrl(a: AttachmentItem): string {
return a.fileId ? `${config.isMock ? "" : config.serviceHost}/api/file/Preview?id=${a.fileId}` : a.fileUrl;
},
onSuccess(resp: FileUploadResp, file: any) {
if (!resp || resp.code !== 0 || !resp.data) {
Message.error(resp?.msg || "上传失败");
return;
}
const d = resp.data;
const item: AttachmentItem = {
fileId: d.fileid,
fileUrl: `/api/file/Preview?id=${d.fileid}`,
fileType: this.imageType(d) ? "image" : "file",
fileName: d.name || file.name,
sort: this.modelValue.length,
};
this.$emit("update:modelValue", [...this.modelValue, item]);
},
imageType(d: FileUploadResp["data"]): boolean {
const t = String(d.type || "").toLowerCase();
if (t.startsWith("image")) return true;
return /\.(jpe?g|gif|png|bmp|webp)$/i.test(d.name || d.fileurl || "");
},
onRemove(file: any) {
// 回显项挂 _item;刚上传项从 response.data.fileid 匹配
const target: AttachmentItem | undefined = file._item || (file.response?.data ? { fileId: file.response.data.fileid } as AttachmentItem : undefined);
if (!target) return;
const arr = this.modelValue.filter((a) => a !== target && (target.fileId ? a.fileId !== target.fileId : a.fileUrl !== target.fileUrl));
this.$emit("update:modelValue", arr.map((a, i) => ({ ...a, sort: i })));
},
onFormatError() {
Message.error(this.imageOnly ? "仅支持图片文件" : "不支持的上传类型!");
},
onExceeded() {
Message.warning("文件大小超过 200MB 限制");
},
},
};
</script>
<style lang="scss" scoped>
.attachment-upload {
display: inline-block;
width: 100%;
:deep(.ivu-upload) {
display: inline-flex;
align-items: center;
}
:deep(.ivu-upload-list) {
display: block;
margin-top: 8px;
}
:deep(.ivu-upload-list-file) {
padding: 4px 0;
}
.upload-tip {
margin-left: 10px;
color: #f90;
font-size: 12px;
line-height: 1;
}
}
</style>