|
|
@@ -0,0 +1,189 @@
|
|
|
+<template>
|
|
|
+ <BsSubTableInput
|
|
|
+ :table-options="tableOptions"
|
|
|
+ :value="value"
|
|
|
+ :is-show-add-btn="false"
|
|
|
+ :is-show-batch-delete-btn="false"
|
|
|
+ :opt-btn-slots="batchTableOptBtnSlots"
|
|
|
+ :is-edit-row="false"
|
|
|
+ @sub-table-input-change="handleTableChange"
|
|
|
+ ref="subTableRef"
|
|
|
+ >
|
|
|
+ <template #custom1>
|
|
|
+ <div class="w-full flex items-center justify-center">
|
|
|
+ <FileUpload listType="text" :showUploadList="false" @change="handleChange" class="w-full file-btn">
|
|
|
+ <template #customUploadBtnSlot>
|
|
|
+ <a-button type="text" style="width: 100%">
|
|
|
+ <template #icon>
|
|
|
+ <upload-outlined />
|
|
|
+ </template>
|
|
|
+ <span>上传文件</span></a-button
|
|
|
+ >
|
|
|
+ </template>
|
|
|
+ </FileUpload>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <template #custom2>
|
|
|
+ <a-button type="text" style="width: 100%" :disabled="!isSelectedData" @click="handleDeleteBatch">
|
|
|
+ <template #icon> <DeleteOutlined /></template>
|
|
|
+ <span>批量删除</span>
|
|
|
+ </a-button>
|
|
|
+ </template>
|
|
|
+ </BsSubTableInput>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+ import { computed, h, ref, watch } from 'vue';
|
|
|
+ import { BsSubTableInput, useBsTable } from '/@/components/BsUi/index.js';
|
|
|
+ import { DISPLAY_STATE } from '/@/components/BsUi/constant.js';
|
|
|
+ import FileUpload from '/@/components/support/file-upload/index.vue';
|
|
|
+ import { cloneDeep, isEmpty, uniqBy } from 'lodash';
|
|
|
+ import { DeleteOutlined } from '@ant-design/icons-vue';
|
|
|
+
|
|
|
+ const props = defineProps({
|
|
|
+ value: {
|
|
|
+ type: Array,
|
|
|
+ default: () => [],
|
|
|
+ },
|
|
|
+ });
|
|
|
+
|
|
|
+ const subTableRef = ref(null);
|
|
|
+
|
|
|
+ const isSelectedData = computed(() => {
|
|
|
+ return isEmpty(subTableRef.value?.selectedData) ? false : subTableRef.value?.selectedData.length !== 0;
|
|
|
+ });
|
|
|
+
|
|
|
+ const rowKey = computed(() => {
|
|
|
+ return tableOptions.gridOptions?.rowKey || 'fileId';
|
|
|
+ });
|
|
|
+
|
|
|
+ const emits = defineEmits(['change', 'update:value']);
|
|
|
+
|
|
|
+ const batchTableOptBtnSlots = ref(['custom1', 'custom2']);
|
|
|
+
|
|
|
+ const { tableOptions, refreshTable } = useBsTable({
|
|
|
+ tableOptions: {
|
|
|
+ gridOptions: {
|
|
|
+ loading: false,
|
|
|
+ columns: [
|
|
|
+ {
|
|
|
+ field: 'fileId',
|
|
|
+ width: '80px',
|
|
|
+ align: 'center',
|
|
|
+ title: 'ID',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ field: 'fileName',
|
|
|
+ title: '文件名称',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ field: 'fileType',
|
|
|
+ width: '150px',
|
|
|
+ title: '文件类型',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ field: 'fileSize',
|
|
|
+ width: '150px',
|
|
|
+ title: '文件大小(M)',
|
|
|
+ align: 'center',
|
|
|
+ slots: {
|
|
|
+ default: ({ row }) => (Number(row.fileSize) / (1024 * 1024)).toFixed(3),
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ fixed: 'right',
|
|
|
+ cellRender: {
|
|
|
+ name: 'CellOption',
|
|
|
+ extraProps: {
|
|
|
+ buttons: [
|
|
|
+ {
|
|
|
+ title: '预览',
|
|
|
+ code: 'view',
|
|
|
+ display: ({ row }) => {
|
|
|
+ return DISPLAY_STATE.VISIBLE;
|
|
|
+ },
|
|
|
+ disabled({ row }) {
|
|
|
+ return false;
|
|
|
+ },
|
|
|
+ onClick({ row }) {},
|
|
|
+ extraProps: {},
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '删除',
|
|
|
+ code: 'delete',
|
|
|
+ display: ({ row }) => {
|
|
|
+ return DISPLAY_STATE.VISIBLE;
|
|
|
+ },
|
|
|
+ disabled({ row }) {
|
|
|
+ return false;
|
|
|
+ },
|
|
|
+ onClick({ row }) {
|
|
|
+ handleDelete(row);
|
|
|
+ },
|
|
|
+ extraProps: {
|
|
|
+ danger: true,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ data: [],
|
|
|
+ rowKey: 'fileId',
|
|
|
+ },
|
|
|
+ request: loadTable,
|
|
|
+ },
|
|
|
+ });
|
|
|
+
|
|
|
+ const handleChange = (files) => {
|
|
|
+ const oldFiles = [...files, ...props.value];
|
|
|
+ const newFiles = cloneDeep(uniqBy(oldFiles, rowKey.value));
|
|
|
+ emits('update:value', newFiles);
|
|
|
+ emits('change', newFiles);
|
|
|
+ };
|
|
|
+
|
|
|
+ async function loadTable() {
|
|
|
+ return {
|
|
|
+ list: props.value,
|
|
|
+ total: props.value.length,
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ const handleDeleteBatch = () => {
|
|
|
+ subTableRef.value.deleteBatch();
|
|
|
+ };
|
|
|
+
|
|
|
+ function handleDelete(row) {
|
|
|
+ const delIndex = props.value.findIndex((v) => v[rowKey.value] === row[rowKey.value]);
|
|
|
+ subTableRef.value.deleteRow(delIndex);
|
|
|
+ }
|
|
|
+
|
|
|
+ function handleTableChange(value) {
|
|
|
+ emits('update:value', value);
|
|
|
+ emits('change', value);
|
|
|
+ }
|
|
|
+
|
|
|
+ watch(
|
|
|
+ () => props.value,
|
|
|
+ (newVal) => {
|
|
|
+ refreshTable();
|
|
|
+ },
|
|
|
+ {
|
|
|
+ immediate: true,
|
|
|
+ }
|
|
|
+ );
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="scss">
|
|
|
+ .file-btn {
|
|
|
+ :deep(.ant-upload-wrapper) {
|
|
|
+ display: block;
|
|
|
+ flex: 1;
|
|
|
+ }
|
|
|
+ :deep(.ant-upload) {
|
|
|
+ display: block;
|
|
|
+ flex: 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+</style>
|