automated_uniapp/uni_modules/cool-ui/components/cl-upload/cl-upload.vue

346 lines
6.4 KiB
Vue
Raw Normal View History

2025-01-09 16:16:11 +08:00
<template>
<view
class="cl-upload-list"
:class="[
{
'is-disabled': isDisabled,
},
]"
>
<!-- 上传列表 -->
<view
class="cl-upload"
v-for="(item, index) in list"
:key="item.uid"
:style="{
height: parseRpx(size[0]),
width: parseRpx(size[1]),
}"
@tap="choose(index)"
>
<!-- 图片 -->
<image class="cl-upload__target" v-show="item.url" :src="item.url" :mode="imageMode" />
<!-- 移除 -->
<text
class="cl-upload__remove cl-icon-toast-error"
@tap.stop="remove(index)"
v-if="!isDisabled"
></text>
<!-- 进度 -->
<view class="cl-upload__progress" v-if="item.progress < 100">
<cl-progress :value="item.progress" :show-text="false"></cl-progress>
</view>
</view>
<!-- 添加按钮 -->
<view
class="cl-upload"
:style="{
height: parseRpx(size[0]),
width: parseRpx(size[1]),
}"
@tap="choose()"
v-if="isAppend"
>
<slot>
<view class="cl-upload__demo">
<text class="cl-icon-camera-fill"></text>
<text class="text" v-if="text">{{ text }}</text>
</view>
</slot>
</view>
</view>
</template>
<script lang="ts">
import { type PropType, computed, defineComponent, ref, watch } from "vue";
import { parseRpx, uuid } from "/@/cool/utils";
import { isArray } from "lodash-es";
import { upload } from "/@/cool";
import { useForm } from "../../hooks";
export default defineComponent({
name: "cl-upload",
props: {
// 绑定值
modelValue: [String, Array],
// 文本
text: {
type: String,
default: "上传/拍摄",
},
// 压缩方式
sizeType: {
type: [String, Array] as PropType<string[] | string>,
default: () => ["original", "compressed"],
},
// 选择方式
sourceType: {
type: Array as PropType<string[]>,
default: () => ["album", "camera"],
},
// 大小
size: {
type: Array,
default: () => [200, 200],
},
// 裁剪模式
imageMode: {
type: String,
default: "aspectFill",
},
// 是否多选
multiple: Boolean,
// 最大允许上传个数
limit: {
type: Number,
default: 9,
},
// 上传的地址
action: String,
// 设置上传的请求头部
headers: Object,
// 上传时附带的额外参数
data: Object,
// 上传的文件字段名
name: {
type: String,
default: "file",
},
// 是否禁用
disabled: {
type: Boolean,
default: null,
},
// 是否自动上传
autoUpload: {
type: Boolean,
default: true,
},
// 演示下测试使用
test: Boolean,
},
emits: [
"update:modelValue",
"change",
"exceed",
"success",
"error",
"upload",
"remove",
"progress",
],
setup(props, { emit }) {
const { disabled } = useForm();
// 图片列表
const list = ref<any[]>([]);
// 下标
const index = ref();
// 是否禁用
const isDisabled = computed(() => disabled.value || props.disabled);
// 监听值
watch(
() => props.modelValue,
(val: any) => {
if (val) {
const _list = list.value;
const arr: string[] = isArray(val) ? val : val.split(",");
list.value = arr
.map((e: string) => {
const d = _list.find((a) => a.url == e);
return {
uid: d ? d.uid : uuid(),
url: e,
progress: 100,
};
})
.filter((e) => e.url);
}
},
{
immediate: true,
},
);
// 能否追加
const isAppend = computed(() => {
const n = list.value.length;
if (isDisabled.value) {
return n == 0;
} else {
return n < (props.multiple ? props.limit : 1);
}
});
// 选择
function choose(i?: number) {
if (isDisabled.value) {
return false;
}
index.value = i;
// 可选数量
const count = index.value === undefined ? props.limit - list.value.length : 1;
// 可选数量验证
if (count <= 0) {
emit("exceed", list.value);
return false;
}
uni.chooseImage({
sizeType: props.sizeType,
sourceType: props.sourceType,
count,
success(res: any) {
// 文件信息
res.tempFiles.forEach(async (file: any) => {
// 预览
const uid = append(file.path);
// 成功
function done(url: string) {
if (url) {
update(uid, { url, progress: 100 });
emit("success", url, file);
} else {
fail();
}
}
// 失败
function fail(message: string | any = "图片地址错误") {
emit("error", message);
remove(list.value.findIndex((e) => e.uid == uid));
}
if (props.test) {
return done(file.path);
}
if (props.action) {
const task = uni.uploadFile({
url: props.action || "",
filePath: file.path,
name: props.name,
header: props.headers,
formData: props.data,
success: (res: any) => {
const { data } = JSON.parse(res.data);
done(data);
},
fail,
});
task.onProgressUpdate((res) => {
emit("progress", res);
});
} else {
if (props.autoUpload) {
// 自动上传
upload(file, {
onProgressUpdate: ({ progress }: any) => {
update(uid, { progress });
},
})
.then(done)
.catch(fail);
} else {
// 自定义上传
emit("upload", { file, done, fail, update, uid });
}
}
});
},
});
}
// 添加
function append(url: string) {
let d: any = {};
if (index.value !== undefined) {
d = list.value[index.value];
d.progress = 0;
d.url = url;
} else {
d = {
uid: uuid(),
url,
progress: 0,
};
list.value.push(d);
}
return d.uid;
}
// 更新
function update(uid: string, data?: any) {
const d = list.value.find((e) => e.uid == uid);
if (d) {
Object.assign(d, data);
if (d.progress == 100) {
change();
}
}
}
// 移除
function remove(index: number) {
if (disabled.value) {
return false;
}
list.value.splice(index, 1);
emit("remove", index);
change();
}
// 检测是否上传完成
function check() {
return list.value.find((e) => e.progress != 100);
}
// 完成
function change() {
if (!check()) {
const v = props.multiple ? list.value.map((e) => e.url) : list.value[0]?.url;
emit("update:modelValue", v);
emit("change", v);
}
}
return {
isDisabled,
list,
index,
isAppend,
check,
choose,
update,
remove,
parseRpx,
};
},
});
</script>