- 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(附件上传)——尚未挂路由,页面切换随后续阶段
130 lines
4.9 KiB
Vue
130 lines
4.9 KiB
Vue
<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>
|