Browse Source

重构底层上传组件,支持表格动态渲染

master
wangxiang 3 years ago
parent
commit
2b1a47a096
  1. 4
      src/api/platform/core/entity/upload.ts
  2. 2
      src/api/platform/system/controller/file.ts
  3. 2
      src/components/AMap/src/AMapDesigner/index.vue
  4. 75
      src/components/AMap/src/amap.data.ts
  5. 20
      src/components/AMap/src/components/TaskModal.vue
  6. 2
      src/components/Table/src/componentMap.ts
  7. 2
      src/components/Table/src/components/editable/EditableCell.vue
  8. 3
      src/components/Table/src/types/componentType.ts
  9. 35
      src/components/Upload/src/UploadModal.vue
  10. 13
      src/components/Upload/src/UploadPreviewModal.vue
  11. 29
      src/components/Upload/src/data.tsx
  12. 2
      src/components/Upload/src/helper.ts
  13. 4
      src/components/Upload/src/typing.ts

4
src/api/platform/core/entity/upload.ts

@ -8,7 +8,7 @@
/** oss上传返回结果对象 */ /** oss上传返回结果对象 */
export interface UploadResult { export interface UploadResult {
message: string; bucketName: string;
code: number; fileName: string;
url: string; url: string;
} }

2
src/api/platform/system/controller/file.ts

@ -20,7 +20,7 @@ enum Api {
export const listFile = (params?: Partial<FileParams>) => defHttp.get<FileResult>({ url: Api.list, params }, { isReturnResultResponse: true }); export const listFile = (params?: Partial<FileParams>) => defHttp.get<FileResult>({ url: Api.list, params }, { isReturnResultResponse: true });
/** 获取文件 */ /** 获取文件 */
export const getFile = (bucket: string, fileName: string) => Promise.resolve(downloadByUrl({ url: `${apiUrl}/${Api.get}/${bucket}/${fileName}`, fileName: fileName })); export const getFile = (bucket: string, fileName: string) => Promise.resolve(downloadByUrl({ url: `${apiUrl}${Api.get}/${bucket}/${fileName}`, fileName: fileName }));
/** 获取本地模板文件 */ /** 获取本地模板文件 */
export const getLocalFile = (fileName: string) => defHttp.get({ url: `${Api.getLocal}/${fileName}` }); export const getLocalFile = (fileName: string) => defHttp.get({ url: `${Api.getLocal}/${fileName}` });

2
src/components/AMap/src/AMapDesigner/index.vue

@ -82,7 +82,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import AMapLoader from '@amap/amap-jsapi-loader'; import AMapLoader from '@amap/amap-jsapi-loader';
import {reactive, watchEffect, getCurrentInstance, onBeforeMount, onUnmounted, ref} from 'vue'; import { reactive, watchEffect, getCurrentInstance, onBeforeMount, onUnmounted, ref } from 'vue';
import { columns } from '../amap.data'; import { columns } from '../amap.data';
import hospital from '/@/assets/images/hospital.svg'; import hospital from '/@/assets/images/hospital.svg';
import medicalKit from '/@/assets/images/medical-kit.svg'; import medicalKit from '/@/assets/images/medical-kit.svg';

75
src/components/AMap/src/amap.data.ts

@ -1,4 +1,8 @@
import { BasicColumn } from '/@/components/Table'; import { BasicColumn } from '/@/components/Table';
import { listHospital } from '/@/api/platform/common/controller/hospital';
import { listUser } from '/@/api/platform/system/controller/user';
import { listOrg } from '/@/api/platform/common/controller/org';
import { commonUpload } from '/@/api/platform/core/controller/upload';
/** /**
* @program: kicc-ui * @program: kicc-ui
@ -38,55 +42,49 @@ export const columns: BasicColumn[] = [
/** 表格普通任务列 */ /** 表格普通任务列 */
export const taskColumns: BasicColumn[] = [ export const taskColumns: BasicColumn[] = [
{ {
title: '下级医院', title: '医院',
dataIndex: 'small_hospital_id', dataIndex: 'hospitalId',
editRow: true, editRow: true,
editRule: true, editRule: true,
editComponent: 'Select', editComponent: 'ApiSelect',
editComponentProps: { editComponentProps: {
options: [ api: listHospital,
{ params: { size: 40 },
label: 'Option1', labelField: 'name',
value: '1' valueField: 'id',
}, resultField: 'data'
{
label: 'Option2',
value: '2'
},
{
label: 'Option3',
value: '3'
}
]
} }
}, },
{ {
title: '上级医院', title: '医检',
dataIndex: 'largeHospitalId', dataIndex: 'orgId',
editRow: true, editRow: true,
editRule: true, editComponent: 'ApiSelect',
editComponent: 'Select',
editComponentProps: { editComponentProps: {
options: [ api: listOrg,
{ params: { size: 40 },
label: 'Option1', labelField: 'name',
value: '1' valueField: 'id',
}, resultField: 'data'
{
label: 'Option2',
value: '2'
},
{
label: 'Option3',
value: '3'
}
]
} }
}, },
{ {
title: '上传文件', title: '上传文件',
dataIndex: 'file' dataIndex: 'fileId',
editRow: true,
editComponent: 'Upload',
editComponentProps: {
multiple: true,
maxSize: 20,
maxNumber: 10,
showUploadSaveBtn: true,
showPreviewNumber: false,
emptyHidePreview: true,
api: commonUpload,
accept: ['image/*']
}
}, },
// todo: 第二版功能
/*{ /*{
title: '要求时间', title: '要求时间',
dataIndex: 'timeRequired', dataIndex: 'timeRequired',
@ -215,7 +213,8 @@ export const formMutualTaskSettingColumns: BasicColumn[] = [
] ]
} }
}, },
{ // todo: 第二版功能
/*{
title: '要求时间', title: '要求时间',
dataIndex: 'timeRequired', dataIndex: 'timeRequired',
editRow: true, editRow: true,
@ -224,7 +223,7 @@ export const formMutualTaskSettingColumns: BasicColumn[] = [
valueFormat: 'YYYY-MM-DD', valueFormat: 'YYYY-MM-DD',
format: 'YYYY-MM-DD', format: 'YYYY-MM-DD',
} }
} }*/
]; ];
export const formMapDataSettingsColumns = [ export const formMapDataSettingsColumns = [

20
src/components/AMap/src/components/TaskModal.vue

@ -38,7 +38,7 @@
import { reactive } from 'vue'; import { reactive } from 'vue';
import {BasicModal, ModalProps, useModal, useModalInner} from '/@/components/Modal'; import {BasicModal, ModalProps, useModal, useModalInner} from '/@/components/Modal';
import { BasicTable, useTable, EditRecordRow, BasicColumn, ActionItem, TableAction } from '/@/components/Table'; import { BasicTable, useTable, EditRecordRow, BasicColumn, ActionItem, TableAction } from '/@/components/Table';
import { formTaskColumns, formMutualTaskColumns, largeHospitalMapList, smallHospitalMapList, } from '../amap.data'; import { taskColumns, taskPresetColumns, largeHospitalMapList, smallHospitalMapList, } from '../amap.data';
import { buildUUID } from '/@/utils/uuid'; import { buildUUID } from '/@/utils/uuid';
import TaskPresetModal from './TaskPresetModal.vue'; import TaskPresetModal from './TaskPresetModal.vue';
@ -71,7 +71,7 @@
const [taskPresetRegisterModal, { openModal }] = useModal(); const [taskPresetRegisterModal, { openModal }] = useModal();
const [registerTable, { reload, getDataSource }] = useTable({ const [registerTable, { reload, getDataSource }] = useTable({
title: '普通任务', title: '普通任务',
columns: formTaskColumns, columns: taskColumns,
pagination: { pagination: {
pageSize: 3, pageSize: 3,
showSizeChanger: false showSizeChanger: false
@ -91,7 +91,7 @@
}); });
const [schemeRegisterTable, { reload: schemeReload, getDataSource: getMutualDataSource, setProps }] = useTable({ const [schemeRegisterTable, { reload: schemeReload, getDataSource: getMutualDataSource, setProps }] = useTable({
title: '交接任务', title: '交接任务',
columns: formMutualTaskColumns, columns: taskPresetColumns,
pagination: { pagination: {
pageSize: 3, pageSize: 3,
showSizeChanger: false showSizeChanger: false
@ -113,16 +113,18 @@
/** 处理任务新增 */ /** 处理任务新增 */
function handleTaskAdd() { function handleTaskAdd() {
getDataSource().push({ getDataSource().push({
smallHospitalId: '', hospitalId: '',
largeHospitalId: '' orgId: '',
fileId: []
}); });
} }
/** 处理任务新增 */ /** 处理任务新增 */
function handleMutualTaskAdd() { function handleMutualTaskAdd() {
getMutualDataSource().push({ getMutualDataSource().push({
smallHospitalId: '', hospitalId: '',
largeHospitalId: '' orgId: '',
fileId: []
}); });
} }
@ -226,9 +228,9 @@
taskDataSource.forEach(item => { taskDataSource.forEach(item => {
// ID // ID
const key = buildUUID(); const key = buildUUID();
const smallHospital = smallHospitalMapList.find(index => index.id == item.smallHospitalId); const smallHospital = smallHospitalMapList.find(index => index.id == item.hospitalId);
if(smallHospital) smallHospitalPositions.push([key, new AMap.LngLat(smallHospital.lng, smallHospital.lat)]); if(smallHospital) smallHospitalPositions.push([key, new AMap.LngLat(smallHospital.lng, smallHospital.lat)]);
const largeHospital = largeHospitalMapList.find(index => index.id == item.largeHospitalId); const largeHospital = largeHospitalMapList.find(index => index.id == item.orgId);
if(largeHospital) largeHospitalPositions.push([key, new AMap.LngLat(largeHospital.lng, largeHospital.lat)]); if(largeHospital) largeHospitalPositions.push([key, new AMap.LngLat(largeHospital.lng, largeHospital.lat)]);
}); });
// //

2
src/components/Table/src/componentMap.ts

@ -10,6 +10,7 @@ import {
} from 'ant-design-vue'; } from 'ant-design-vue';
import type { ComponentType } from './types/componentType'; import type { ComponentType } from './types/componentType';
import { ApiSelect, ApiTreeSelect } from '/@/components/Form'; import { ApiSelect, ApiTreeSelect } from '/@/components/Form';
import { BasicUpload } from "/@/components/Upload";
const componentMap = new Map<ComponentType, Component>(); const componentMap = new Map<ComponentType, Component>();
@ -22,6 +23,7 @@ componentMap.set('Switch', Switch);
componentMap.set('Checkbox', Checkbox); componentMap.set('Checkbox', Checkbox);
componentMap.set('DatePicker', DatePicker); componentMap.set('DatePicker', DatePicker);
componentMap.set('TimePicker', TimePicker); componentMap.set('TimePicker', TimePicker);
componentMap.set('Upload', BasicUpload);
export function add(compName: ComponentType, component: Component) { export function add(compName: ComponentType, component: Component) {
componentMap.set(compName, component); componentMap.set(compName, component);

2
src/components/Table/src/components/editable/EditableCell.vue

@ -187,7 +187,7 @@
currentValueRef.value = (e as ChangeEvent).target.value; currentValueRef.value = (e as ChangeEvent).target.value;
} else if (component === 'Checkbox') { } else if (component === 'Checkbox') {
currentValueRef.value = (e as ChangeEvent).target.checked; currentValueRef.value = (e as ChangeEvent).target.checked;
} else if (isString(e) || isBoolean(e) || isNumber(e)) { } else if (isString(e) || isBoolean(e) || isNumber(e) || isArray(e)) {
currentValueRef.value = e; currentValueRef.value = e;
} }
const onChange = props.column?.editComponentProps?.onChange; const onChange = props.column?.editComponentProps?.onChange;

3
src/components/Table/src/types/componentType.ts

@ -7,4 +7,5 @@ export type ComponentType =
| 'Checkbox' | 'Checkbox'
| 'Switch' | 'Switch'
| 'DatePicker' | 'DatePicker'
| 'TimePicker'; | 'TimePicker'
| 'Upload';

35
src/components/Upload/src/UploadModal.vue

@ -48,32 +48,28 @@
</BasicModal> </BasicModal>
</template> </template>
<script lang="ts"> <script lang="ts">
import {defineComponent, reactive, ref, toRefs, unref, computed, PropType, watch} from 'vue'; import { defineComponent, reactive, ref, toRefs, unref, computed, PropType } from 'vue';
import { Upload, Alert } from 'ant-design-vue'; import { Upload, Alert } from 'ant-design-vue';
import { BasicModal, useModalInner } from '/@/components/Modal'; import { BasicModal, useModalInner } from '/@/components/Modal';
// import { BasicTable, useTable } from '/@/components/Table';
// hooks
import { useUploadType } from './useUpload'; import { useUploadType } from './useUpload';
import { useMessage } from '/@/hooks/web/useMessage'; import { useMessage } from '/@/hooks/web/useMessage';
// types import { FileItem, UploadResultStatus } from './typing';
import {FileItem, PreviewFileItem, UploadResultStatus} from './typing';
import { basicProps } from './props'; import { basicProps } from './props';
import { createTableColumns, createActionColumn } from './data'; import { createTableColumns, createActionColumn } from './data';
// utils
import { checkImgType, getBase64WithFile } from './helper'; import { checkImgType, getBase64WithFile } from './helper';
import { buildUUID } from '/@/utils/uuid'; import { buildUUID } from '/@/utils/uuid';
import {isArray, isFunction} from '/@/utils/is'; import { isFunction } from '/@/utils/is';
import { warn } from '/@/utils/log'; import { warn } from '/@/utils/log';
import FileList from './FileList.vue'; import FileList from './FileList.vue';
import { useI18n } from '/@/hooks/web/useI18n'; import { useI18n } from '/@/hooks/web/useI18n';
import {useTimeoutFn} from '/@/hooks/core/useTimeout'; import { useTimeoutFn } from '/@/hooks/core/useTimeout';
export default defineComponent({ export default defineComponent({
components: { BasicModal, Upload, Alert, FileList }, components: { BasicModal, Upload, Alert, FileList },
props: { props: {
...basicProps, ...basicProps,
previewFileList: { previewFileList: {
type: Array as PropType<string[]>, type: Array as PropType<FileItem[]>,
default: () => [], default: () => [],
}, },
}, },
@ -83,18 +79,11 @@ import {useTimeoutFn} from '/@/hooks/core/useTimeout';
fileList: [], fileList: [],
}); });
// //
const isUploadingRef = ref(false); const isUploadingRef = ref(false);
const fileListRef = ref<FileItem[]>([]); const fileListRef = ref<FileItem[]>([]);
const { accept, helpText, maxNumber, maxSize } = toRefs(props); const { accept, helpText, maxNumber, maxSize } = toRefs(props);
watch(() => props.previewFileList, (value) => {
if (!isArray(value)) value = [];
fileListRef.value = value.filter((item) => !!item);
},
{ immediate: true }
);
const { t } = useI18n(); const { t } = useI18n();
const [register, { closeModal }] = useModalInner(); const [register, { closeModal }] = useModalInner();
@ -155,7 +144,6 @@ import {useTimeoutFn} from '/@/hooks/core/useTimeout';
// //
if (checkImgType(file)) { if (checkImgType(file)) {
// beforeUpload // beforeUpload
// file.thumbUrl = await getBase64(file);
getBase64WithFile(file).then(({ result: thumbUrl }) => { getBase64WithFile(file).then(({ result: thumbUrl }) => {
fileListRef.value = [ fileListRef.value = [
...unref(fileListRef), ...unref(fileListRef),
@ -178,14 +166,6 @@ import {useTimeoutFn} from '/@/hooks/core/useTimeout';
emit('delete', record); emit('delete', record);
} }
//
// function handlePreview(record: FileItem) {
// const { thumbUrl = '' } = record;
// createImgPreview({
// imageList: [thumbUrl],
// });
// }
async function uploadApiByItem(item: FileItem) { async function uploadApiByItem(item: FileItem) {
const { api } = props; const { api } = props;
if (!api || !isFunction(api)) { if (!api || !isFunction(api)) {
@ -252,7 +232,7 @@ import {useTimeoutFn} from '/@/hooks/core/useTimeout';
} }
} }
// //
function handleOk() { function handleOk() {
const { maxNumber } = props; const { maxNumber } = props;
@ -299,7 +279,6 @@ import {useTimeoutFn} from '/@/hooks/core/useTimeout';
getStringAccept, getStringAccept,
getOkButtonProps, getOkButtonProps,
beforeUpload, beforeUpload,
// registerTable,
fileListRef, fileListRef,
state, state,
isUploadingRef, isUploadingRef,

13
src/components/Upload/src/UploadPreviewModal.vue

@ -12,7 +12,6 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, watch, ref } from 'vue'; import { defineComponent, watch, ref } from 'vue';
// import { BasicTable, useTable } from '/@/components/Table';
import FileList from './FileList.vue'; import FileList from './FileList.vue';
import { BasicModal, useModalInner } from '/@/components/Modal'; import { BasicModal, useModalInner } from '/@/components/Modal';
import { previewProps } from './props'; import { previewProps } from './props';
@ -21,6 +20,8 @@
import { createPreviewColumns, createPreviewActionColumn } from './data'; import { createPreviewColumns, createPreviewActionColumn } from './data';
import { useI18n } from '/@/hooks/web/useI18n'; import { useI18n } from '/@/hooks/web/useI18n';
import { isArray } from '/@/utils/is'; import { isArray } from '/@/utils/is';
import { useGlobSetting } from '/@/hooks/setting';
const { apiUrl } = useGlobSetting();
export default defineComponent({ export default defineComponent({
components: { BasicModal, FileList }, components: { BasicModal, FileList },
@ -61,18 +62,10 @@
} }
} }
// //
// function handlePreview(record: PreviewFileItem) {
// const { url = '' } = record;
// createImgPreview({
// imageList: [url],
// });
// }
// //
function handleDownload(record: PreviewFileItem) { function handleDownload(record: PreviewFileItem) {
const { url = '' } = record; const { url = '' } = record;
downloadByUrl({ url }); downloadByUrl({ url: `${apiUrl}${url}` });
} }
return { return {

29
src/components/Upload/src/data.tsx

@ -1,14 +1,12 @@
import type { BasicColumn, ActionItem } from '/@/components/Table'; import type { BasicColumn, ActionItem } from '/@/components/Table';
import { FileItem, PreviewFileItem, UploadResultStatus } from './typing'; import { FileItem, PreviewFileItem, UploadResultStatus } from './typing';
import { import { isImgTypeByName } from './helper';
// checkImgType,
isImgTypeByName,
} from './helper';
import { Progress, Tag } from 'ant-design-vue'; import { Progress, Tag } from 'ant-design-vue';
import TableAction from '/@/components/Table/src/components/TableAction.vue'; import TableAction from '/@/components/Table/src/components/TableAction.vue';
import ThumbUrl from './ThumbUrl.vue'; import ThumbUrl from './ThumbUrl.vue';
import { useI18n } from '/@/hooks/web/useI18n'; import { useI18n } from '/@/hooks/web/useI18n';
import {useGlobSetting} from '/@/hooks/setting';
const { apiUrl } = useGlobSetting();
const { t } = useI18n(); const { t } = useI18n();
// 文件上传列表 // 文件上传列表
@ -20,7 +18,7 @@ export function createTableColumns(): BasicColumn[] {
width: 100, width: 100,
customRender: ({ record }) => { customRender: ({ record }) => {
const { thumbUrl } = (record as FileItem) || {}; const { thumbUrl } = (record as FileItem) || {};
return thumbUrl && <ThumbUrl fileUrl={thumbUrl} />; return thumbUrl && <ThumbUrl fileUrl={ thumbUrl } />;
}, },
}, },
{ {
@ -55,11 +53,6 @@ export function createTableColumns(): BasicColumn[] {
return text && (text / 1024).toFixed(2) + 'KB'; return text && (text / 1024).toFixed(2) + 'KB';
}, },
}, },
// {
// dataIndex: 'type',
// title: '文件类型',
// width: 100,
// },
{ {
dataIndex: 'status', dataIndex: 'status',
title: t('component.upload.fileStatue'), title: t('component.upload.fileStatue'),
@ -92,12 +85,6 @@ export function createActionColumn(handleRemove: Function): BasicColumn {
onClick: handleRemove.bind(null, record), onClick: handleRemove.bind(null, record),
}, },
]; ];
// if (checkImgType(record)) {
// actions.unshift({
// label: t('component.upload.preview'),
// onClick: handlePreview.bind(null, record),
// });
// }
return <TableAction actions={actions} outside={true} />; return <TableAction actions={actions} outside={true} />;
}, },
}; };
@ -111,7 +98,7 @@ export function createPreviewColumns(): BasicColumn[] {
width: 100, width: 100,
customRender: ({ record }) => { customRender: ({ record }) => {
const { url } = (record as PreviewFileItem) || {}; const { url } = (record as PreviewFileItem) || {};
return isImgTypeByName(url) && <ThumbUrl fileUrl={url} />; return isImgTypeByName(url) && <ThumbUrl fileUrl={ apiUrl + url } />;
}, },
}, },
{ {
@ -123,9 +110,9 @@ export function createPreviewColumns(): BasicColumn[] {
} }
export function createPreviewActionColumn({ export function createPreviewActionColumn({
handleRemove, handleRemove,
handleDownload, handleDownload,
}: { }: {
handleRemove: Fn; handleRemove: Fn;
handleDownload: Fn; handleDownload: Fn;
}): BasicColumn { }): BasicColumn {

2
src/components/Upload/src/helper.ts

@ -1,8 +1,6 @@
export function checkFileType(file: File, accepts: string[]) { export function checkFileType(file: File, accepts: string[]) {
const newTypes = accepts.join('|'); const newTypes = accepts.join('|');
// const reg = /\.(jpg|jpeg|png|gif|txt|doc|docx|xls|xlsx|xml)$/i;
const reg = new RegExp('\\.(' + newTypes + ')$', 'i'); const reg = new RegExp('\\.(' + newTypes + ')$', 'i');
return reg.test(file.name); return reg.test(file.name);
} }

4
src/components/Upload/src/typing.ts

@ -1,4 +1,4 @@
import { UploadApiResult } from '/@/api/sys/model/uploadModel'; import { UploadResult } from '/@/api/platform/core/entity/upload';
export enum UploadResultStatus { export enum UploadResultStatus {
SUCCESS = 'success', SUCCESS = 'success',
@ -14,7 +14,7 @@ export interface FileItem {
percent: number; percent: number;
file: File; file: File;
status?: UploadResultStatus; status?: UploadResultStatus;
responseData?: UploadApiResult; responseData?: UploadResult;
uuid: string; uuid: string;
} }

Loading…
Cancel
Save