feat: 更新代码
This commit is contained in:
parent
0516ee998e
commit
71f3e8d415
|
@ -12,6 +12,14 @@ body,
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
.ant-input-affix-wrapper-readonly,
|
||||||
|
.ant-input[readonly],
|
||||||
|
.ant-input-affix-wrapper-readonly .ant-input {
|
||||||
|
background-color: #fafafa;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
*/
|
||||||
@keyframes rotate {
|
@keyframes rotate {
|
||||||
0% {
|
0% {
|
||||||
transform: rotate(0deg)
|
transform: rotate(0deg)
|
||||||
|
|
|
@ -2,13 +2,20 @@
|
||||||
import { watch, ref, onMounted } from 'vue';
|
import { watch, ref, onMounted } from 'vue';
|
||||||
import { Button } from '../../common';
|
import { Button } from '../../common';
|
||||||
import { Modal, Space } from 'ant-design-vue';
|
import { Modal, Space } from 'ant-design-vue';
|
||||||
import { AsyncUploader, EditorData, PageData } from '@skyfox2000/webbase';
|
import { AsyncUploader, EditorData, gridRowUpdate, PageData } from '@skyfox2000/webbase';
|
||||||
import { AnyData, IUrlInfo } from '@skyfox2000/fapi';
|
import { AnyData, ApiResponse, IUrlInfo, ResStatus } from '@skyfox2000/fapi';
|
||||||
import UploadFileList from './uploadList.vue';
|
import UploadFileList from './uploadList.vue';
|
||||||
import { UploadFile } from '@skyfox2000/webbase';
|
import { UploadFile } from '@skyfox2000/webbase';
|
||||||
import message from 'vue-m-message';
|
import message from 'vue-m-message';
|
||||||
|
import { UploadStatus } from '@skyfox2000/webbase';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
/**
|
||||||
|
* #### 使用模式
|
||||||
|
* - Row 数据行
|
||||||
|
* - Page 页面
|
||||||
|
*/
|
||||||
|
mode: 'Row' | 'Page';
|
||||||
/**
|
/**
|
||||||
* 文件后缀限制
|
* 文件后缀限制
|
||||||
*/
|
*/
|
||||||
|
@ -44,6 +51,20 @@ const maxCount = props.maxCount ?? 1;
|
||||||
const maxConcurrent = props.maxConcurrent ?? 3;
|
const maxConcurrent = props.maxConcurrent ?? 3;
|
||||||
|
|
||||||
const fileList = ref<UploadFile[]>([]);
|
const fileList = ref<UploadFile[]>([]);
|
||||||
|
const emit = defineEmits<{
|
||||||
|
/**
|
||||||
|
* 显示预处理
|
||||||
|
*/
|
||||||
|
'before:file-list': [EditorData<any>, UploadFile[]];
|
||||||
|
/**
|
||||||
|
* 上传前预处理
|
||||||
|
*/
|
||||||
|
'before:upload': [UploadFile[]];
|
||||||
|
/**
|
||||||
|
* 上传结束,处理上传后的文件
|
||||||
|
*/
|
||||||
|
'after:upload': [UploadFile[]];
|
||||||
|
}>();
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => uploaderForm.value.visible,
|
() => uploaderForm.value.visible,
|
||||||
|
@ -62,36 +83,64 @@ const dialogUpload = async () => {
|
||||||
if (!url.api) url.api = props.pageData.api;
|
if (!url.api) url.api = props.pageData.api;
|
||||||
if (url.authorize === undefined) url.authorize = props.pageData.authorize;
|
if (url.authorize === undefined) url.authorize = props.pageData.authorize;
|
||||||
|
|
||||||
|
emit('before:upload', fileList.value);
|
||||||
const uploader = new AsyncUploader(url, maxConcurrent);
|
const uploader = new AsyncUploader(url, maxConcurrent);
|
||||||
|
|
||||||
uploaderForm.value.isFormLoading = true;
|
uploaderForm.value.isFormLoading = true;
|
||||||
try {
|
try {
|
||||||
if (fileList.value.length === 0) {
|
if (fileList.value.length === 0) {
|
||||||
message.warning('请选择上传的文件!');
|
message.warning('请选择上传的文件!');
|
||||||
setTimeout(() => {
|
|
||||||
uploaderForm.value.isFormLoading = false;
|
|
||||||
}, 10000);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 开始上传文件
|
// 开始上传文件
|
||||||
await uploader.upload(
|
await uploader.upload(
|
||||||
fileList.value,
|
fileList.value,
|
||||||
(file) => {
|
(_) => {},
|
||||||
console.log(`${file.name} 上传进度:${file.percent}% (${file.status})`);
|
|
||||||
},
|
|
||||||
(files) => {
|
(files) => {
|
||||||
uploaderForm.value.isFormLoading = false;
|
uploaderForm.value.isFormLoading = false;
|
||||||
console.log('所有文件上传结束:', files);
|
let err_count = 0;
|
||||||
|
for (const file of files) {
|
||||||
|
if (file.status === UploadStatus.Error) {
|
||||||
|
err_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!err_count) message.success('全部文件上传成功!');
|
||||||
|
else if (err_count < files.length) message.error('上传结束,部分文件上传失败!');
|
||||||
|
else message.error('上传结束,所有文件上传失败!');
|
||||||
|
// 由外部控制存储字段处理或新建formData对象
|
||||||
|
emit('after:upload', files);
|
||||||
|
dialogSave();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
uploaderForm.value.isFormLoading = false;
|
uploaderForm.value.isFormLoading = false;
|
||||||
console.error('上传错误:', error);
|
console.error('上传错误:', error);
|
||||||
|
message.error('上传错误,请稍后再试!');
|
||||||
|
emit('after:upload', fileList.value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const dialogSave = async () => {
|
||||||
|
switch (props.mode) {
|
||||||
|
case 'Row':
|
||||||
|
if (uploaderForm.value.formData) {
|
||||||
|
// 仅修改上传相关字段
|
||||||
|
const result: ApiResponse<any> = await gridRowUpdate(props.pageData, uploaderForm.value.formData);
|
||||||
|
if (result.status === ResStatus.SUCCESS) {
|
||||||
|
uploaderForm.value.visible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'Page':
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
const list: UploadFile[] = [];
|
||||||
|
emit('before:file-list', uploaderForm.value, list);
|
||||||
|
fileList.value.push(...list);
|
||||||
open.value = uploaderForm.value.visible;
|
open.value = uploaderForm.value.visible;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -106,11 +155,11 @@ const dialogClose = () => {
|
||||||
:wrapClassName="'modal mx-auto ' + ($attrs.width ? 'w-[' + $attrs.width + ']' : 'w-[430px]')"
|
:wrapClassName="'modal mx-auto ' + ($attrs.width ? 'w-[' + $attrs.width + ']' : 'w-[430px]')"
|
||||||
@close="dialogClose"
|
@close="dialogClose"
|
||||||
>
|
>
|
||||||
<UploadFileList v-model:file-list="fileList" :max-count="maxCount" :file-ext="fileExt" />
|
<UploadFileList v-model:file-list="fileList" :page-data="pageData" :max-count="maxCount" :file-ext="fileExt" />
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<Space>
|
<Space>
|
||||||
<Button @click="dialogClose">取消</Button>
|
<Button @click="dialogClose">取消</Button>
|
||||||
<Button @click="dialogUpload" type="primary" :loading="uploaderForm.isFormSaving"> 上传文件 </Button>
|
<Button @click="dialogUpload" type="primary" :loading="uploaderForm.isFormSaving"> 上传文件并保存 </Button>
|
||||||
</Space>
|
</Space>
|
||||||
</template>
|
</template>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
|
@ -1,30 +1,53 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Button } from '@/components';
|
import { Button } from '@/components';
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref, watch } from 'vue';
|
||||||
import message from 'vue-m-message';
|
import message from 'vue-m-message';
|
||||||
import type { UploadProps } from 'ant-design-vue';
|
import type { UploadProps } from 'ant-design-vue';
|
||||||
import { Upload, Progress, Tag } from 'ant-design-vue';
|
import { Upload, Progress, Tag } from 'ant-design-vue';
|
||||||
import { UploadFile, UploadFileStatus } from '@skyfox2000/webbase';
|
import { PageData, UploadFile, UploadStatus, donwloadFromMinio, path } from '@skyfox2000/webbase';
|
||||||
import { watch } from 'vue';
|
import { IUrlInfo } from '@skyfox2000/fapi';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
fileList: UploadFile<any>[];
|
/**
|
||||||
placeholder?: string;
|
* 是否自动上传
|
||||||
fileExt?: string[];
|
*/
|
||||||
maxFileSize?: number;
|
|
||||||
maxCount?: number;
|
|
||||||
autoUpload?: boolean;
|
autoUpload?: boolean;
|
||||||
|
pageData: PageData<any>;
|
||||||
|
/**
|
||||||
|
* 文件列表
|
||||||
|
*/
|
||||||
|
fileList: UploadFile<any>[];
|
||||||
|
/**
|
||||||
|
* 提示文字
|
||||||
|
*/
|
||||||
|
placeholder?: string;
|
||||||
|
/**
|
||||||
|
* 文件后缀列表
|
||||||
|
*/
|
||||||
|
fileExt?: string[];
|
||||||
|
/**
|
||||||
|
* 最大文件大小
|
||||||
|
*/
|
||||||
|
maxFileSize?: number;
|
||||||
|
/**
|
||||||
|
* 最大数量
|
||||||
|
*/
|
||||||
|
maxCount?: number;
|
||||||
|
/**
|
||||||
|
* 文件路径
|
||||||
|
*/
|
||||||
|
parentPath?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
autoUpload: false,
|
||||||
fileList: () => [],
|
fileList: () => [],
|
||||||
placeholder: '',
|
placeholder: '',
|
||||||
maxFileSize: 20,
|
maxFileSize: 20,
|
||||||
maxCount: 5,
|
maxCount: 5,
|
||||||
autoUpload: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const fileList = ref<UploadFile[]>([]);
|
const fileList = ref<UploadFile[]>(props.fileList);
|
||||||
const fileUploader = ref();
|
const fileUploader = ref();
|
||||||
const emit = defineEmits(['update:file-list']);
|
const emit = defineEmits(['update:file-list']);
|
||||||
|
|
||||||
|
@ -44,7 +67,7 @@ const beforeUpload: UploadProps['beforeUpload'] = (file) => {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fileList.value.length >= props.maxCount) {
|
if (props.maxCount > 1 && fileList.value.length >= props.maxCount) {
|
||||||
message.error(`最多上传 ${props.maxCount} 个文件`);
|
message.error(`最多上传 ${props.maxCount} 个文件`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -52,10 +75,18 @@ const beforeUpload: UploadProps['beforeUpload'] = (file) => {
|
||||||
return props.autoUpload;
|
return props.autoUpload;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const updateFileList: UploadProps['onUpdate:fileList'] = (fileList) => {
|
||||||
|
fileList.forEach((file) => {
|
||||||
|
if (!file.fileName) file.fileName = file.name;
|
||||||
|
if (props.parentPath) file.name = path.join('/', props.parentPath, file.fileName);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const uploadProps = computed<UploadProps>(() => ({
|
const uploadProps = computed<UploadProps>(() => ({
|
||||||
accept: acceptString.value,
|
accept: acceptString.value,
|
||||||
multiple: true,
|
multiple: true,
|
||||||
fileList: fileList.value as UploadProps['fileList'],
|
fileList: fileList.value as UploadProps['fileList'],
|
||||||
|
'onUpdate:fileList': updateFileList,
|
||||||
beforeUpload: beforeUpload,
|
beforeUpload: beforeUpload,
|
||||||
listType: 'text',
|
listType: 'text',
|
||||||
maxCount: props.maxCount,
|
maxCount: props.maxCount,
|
||||||
|
@ -75,6 +106,36 @@ watch(
|
||||||
{ deep: true },
|
{ deep: true },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const downloadFile = (index: number) => {
|
||||||
|
const fileInfo = fileList.value[index].minioFile!;
|
||||||
|
const url: IUrlInfo = {
|
||||||
|
api: props.pageData.api,
|
||||||
|
authorize: props.pageData.authorize,
|
||||||
|
url: props.pageData.urls.download!.url,
|
||||||
|
params: {
|
||||||
|
Query: {
|
||||||
|
FileKey: fileInfo.Key,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
donwloadFromMinio(url);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onlineOrOffline = (file: UploadFile) => {
|
||||||
|
file.status = file.status === UploadStatus.Offline ? UploadStatus.Online : UploadStatus.Offline;
|
||||||
|
file.minioFile!.Status = file.status;
|
||||||
|
};
|
||||||
|
|
||||||
|
// const previewFile = (index: number) => {
|
||||||
|
// const fileInfo = fileList.value[index].minioFile;
|
||||||
|
// console.log(fileInfo);
|
||||||
|
// };
|
||||||
|
|
||||||
|
const removeFile = (index: number) => {
|
||||||
|
fileList.value.splice(index, 1);
|
||||||
|
};
|
||||||
|
|
||||||
const getPlaceholder = (): string => {
|
const getPlaceholder = (): string => {
|
||||||
const typeMsg = props.fileExt && props.fileExt.length ? `文件必须为 ${props.fileExt.join('/')}` : '';
|
const typeMsg = props.fileExt && props.fileExt.length ? `文件必须为 ${props.fileExt.join('/')}` : '';
|
||||||
const sizeMsg = props.maxFileSize !== 0 ? `单文件最大 ${props.maxFileSize}MB` : '';
|
const sizeMsg = props.maxFileSize !== 0 ? `单文件最大 ${props.maxFileSize}MB` : '';
|
||||||
|
@ -83,30 +144,34 @@ const getPlaceholder = (): string => {
|
||||||
return [sizeMsg, typeMsg, countMsg].filter(Boolean).join(',');
|
return [sizeMsg, typeMsg, countMsg].filter(Boolean).join(',');
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeFile = (index: number) => {
|
const getStatusColor = (status?: UploadStatus) => {
|
||||||
fileList.value.splice(index, 1);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getStatusColor = (status?: UploadFileStatus) => {
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case UploadFileStatus.Uploading:
|
case UploadStatus.Uploading:
|
||||||
return 'blue';
|
return 'blue';
|
||||||
case UploadFileStatus.Success:
|
case UploadStatus.Success:
|
||||||
return 'green';
|
return 'green';
|
||||||
case UploadFileStatus.Error:
|
case UploadStatus.Error:
|
||||||
return 'red';
|
return 'red';
|
||||||
|
case UploadStatus.Online:
|
||||||
|
return 'green';
|
||||||
|
case UploadStatus.Offline:
|
||||||
|
return 'pink';
|
||||||
default:
|
default:
|
||||||
return 'cyan';
|
return 'cyan';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const getStatus = (status?: UploadFileStatus) => {
|
const getStatus = (status?: UploadStatus) => {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case UploadFileStatus.Uploading:
|
case UploadStatus.Uploading:
|
||||||
return '上传中';
|
return '上传中';
|
||||||
case UploadFileStatus.Success:
|
case UploadStatus.Success:
|
||||||
return '已完成';
|
return '已完成';
|
||||||
case UploadFileStatus.Error:
|
case UploadStatus.Error:
|
||||||
return '上传失败';
|
return '上传失败';
|
||||||
|
case UploadStatus.Online:
|
||||||
|
return '在线';
|
||||||
|
case UploadStatus.Offline:
|
||||||
|
return '已下线';
|
||||||
default:
|
default:
|
||||||
return '待上传';
|
return '待上传';
|
||||||
}
|
}
|
||||||
|
@ -129,20 +194,36 @@ const getStatus = (status?: UploadFileStatus) => {
|
||||||
<div v-for="(file, index) in fileList" :key="index" class="mb-2 pb-1">
|
<div v-for="(file, index) in fileList" :key="index" class="mb-2 pb-1">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<span class="text-gray-700 mr-2">{{ file.name }}</span>
|
<span
|
||||||
|
class="text-gray-700 mr-2"
|
||||||
|
:class="[file.status == UploadStatus.Offline ? 'line-through' : '']"
|
||||||
|
>{{ file.fileName ?? file.name }}</span
|
||||||
|
>
|
||||||
<span>
|
<span>
|
||||||
<Tag :color="getStatusColor(file.status)">{{ getStatus(file.status) }}</Tag>
|
<Tag :color="getStatusColor(file.status)">{{ getStatus(file.status) }}</Tag>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<!-- <span class="text-blue-500 hover:text-blue-700 mr-4">预览</span> -->
|
<span
|
||||||
|
class="text-blue-500 hover:text-blue-700 mr-4 cursor-pointer"
|
||||||
|
v-if="file.status == UploadStatus.Offline || file.status == UploadStatus.Online"
|
||||||
|
@click="onlineOrOffline(file)"
|
||||||
|
>{{ file.status == UploadStatus.Offline ? '上线' : '下线' }}</span
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
v-if="file.status == UploadStatus.Offline || file.status == UploadStatus.Online"
|
||||||
|
class="text-blue-500 hover:text-blue-700 mr-4 cursor-pointer"
|
||||||
|
@click="downloadFile(index)"
|
||||||
|
>下载</span
|
||||||
|
>
|
||||||
|
<!-- <span class="text-blue-500 hover:text-blue-700 mr-4" @click="previewFile(index)">预览</span> -->
|
||||||
<span class="text-red-500 hover:text-red-700 cursor-pointer" @click="removeFile(index)">删除</span>
|
<span class="text-red-500 hover:text-red-700 cursor-pointer" @click="removeFile(index)">删除</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 上传进度条 -->
|
<!-- 上传进度条 -->
|
||||||
<div>
|
<div>
|
||||||
<Progress :percent="file.percent" :stroke-width="2" :show-info="false" style="height: 2px" />
|
<Progress :percent="file.percent" :stroke-width="2" :show-info="false" style="height: 2px"></Progress>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -86,6 +86,7 @@ const disabled = (item: ButtonTool) => {
|
||||||
<Space>
|
<Space>
|
||||||
<template v-for="item in Buttons" :key="item.key">
|
<template v-for="item in Buttons" :key="item.key">
|
||||||
<Popconfirm
|
<Popconfirm
|
||||||
|
v-if="getToolVisible(item, props.record)"
|
||||||
:disabled="!item.confirm"
|
:disabled="!item.confirm"
|
||||||
cancelText="否"
|
cancelText="否"
|
||||||
okText="是"
|
okText="是"
|
||||||
|
@ -98,7 +99,7 @@ const disabled = (item: ButtonTool) => {
|
||||||
:key="item.key"
|
:key="item.key"
|
||||||
:type="item.type ?? 'text'"
|
:type="item.type ?? 'text'"
|
||||||
:danger="item.danger"
|
:danger="item.danger"
|
||||||
v-if="getToolVisible(item)"
|
v-if="getToolVisible(item, props.record)"
|
||||||
:disabled="disabled(item)"
|
:disabled="disabled(item)"
|
||||||
@click="onToolClicked(item, pageData, props.record)"
|
@click="onToolClicked(item, pageData, props.record)"
|
||||||
size="small"
|
size="small"
|
||||||
|
@ -118,7 +119,7 @@ const disabled = (item: ButtonTool) => {
|
||||||
<Menu>
|
<Menu>
|
||||||
<template v-for="item in Menus" :key="item.key">
|
<template v-for="item in Menus" :key="item.key">
|
||||||
<MenuItem
|
<MenuItem
|
||||||
v-if="getToolVisible(item)"
|
v-if="getToolVisible(item, props.record)"
|
||||||
:disabled="disabled(item)"
|
:disabled="disabled(item)"
|
||||||
@click="onToolClicked(item, pageData, props.record)"
|
@click="onToolClicked(item, pageData, props.record)"
|
||||||
>
|
>
|
||||||
|
|
|
@ -45,7 +45,7 @@ const onClear = () => {
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<Input
|
<Input
|
||||||
:class="errClass === 'error' ? ['error', '!border-red-300', 'shadow-[0_0_3px_0px_#ff4d4f]'] : ''"
|
:class="[errClass === 'error' ? 'error !border-red-300 shadow-[0_0_3px_0px_#ff4d4f]' : '']"
|
||||||
v-model:value="innerValue"
|
v-model:value="innerValue"
|
||||||
@change="onClear"
|
@change="onClear"
|
||||||
:allow-clear="true"
|
:allow-clear="true"
|
||||||
|
|
|
@ -53,6 +53,10 @@ declare global {
|
||||||
* 订单ID
|
* 订单ID
|
||||||
*/
|
*/
|
||||||
Id: string | null;
|
Id: string | null;
|
||||||
|
/**
|
||||||
|
* 订单号
|
||||||
|
*/
|
||||||
|
OrderNo: string | null;
|
||||||
/**
|
/**
|
||||||
* 所属会员
|
* 所属会员
|
||||||
*/
|
*/
|
||||||
|
@ -61,6 +65,10 @@ declare global {
|
||||||
* 所属会员
|
* 所属会员
|
||||||
*/
|
*/
|
||||||
MemberName: string | null;
|
MemberName: string | null;
|
||||||
|
/**
|
||||||
|
* 手机号
|
||||||
|
*/
|
||||||
|
Mobile: string | null;
|
||||||
/**
|
/**
|
||||||
* 价码ID
|
* 价码ID
|
||||||
*/
|
*/
|
||||||
|
@ -84,11 +92,11 @@ declare global {
|
||||||
/**
|
/**
|
||||||
* 快递地址信息
|
* 快递地址信息
|
||||||
*/
|
*/
|
||||||
ExpressInfo?: { [key: string]: any };
|
ExpressInfo?: Record;
|
||||||
/**
|
/**
|
||||||
* 检查报告
|
* 检查报告
|
||||||
*/
|
*/
|
||||||
ReportFileUrl?: string | null;
|
ReportFile?: MinioFile[];
|
||||||
/**
|
/**
|
||||||
* 订单状态
|
* 订单状态
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -24,6 +24,12 @@ export const SamplingHelperUrl: ApiUrls = {
|
||||||
save: {
|
save: {
|
||||||
url: '/api/RCSamplingHelperSrv/save',
|
url: '/api/RCSamplingHelperSrv/save',
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* 更新地址
|
||||||
|
*/
|
||||||
|
update: {
|
||||||
|
url: '/api/RCSamplingHelperSrv/update',
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* 删除地址
|
* 删除地址
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -10,14 +10,20 @@ const formData = ref<OrderEntity>(editorData.formData);
|
||||||
<template>
|
<template>
|
||||||
<Drawer title="订单信息" :page-data="pageData">
|
<Drawer title="订单信息" :page-data="pageData">
|
||||||
<Form>
|
<Form>
|
||||||
|
<FormItem label="订单号">
|
||||||
|
<Input v-model:value="formData.OrderNo" disabled />
|
||||||
|
</FormItem>
|
||||||
<FormItem label="会员名">
|
<FormItem label="会员名">
|
||||||
<Input v-model:value="formData.MemberName" />
|
<Input v-model:value="formData.MemberName" disabled />
|
||||||
|
</FormItem>
|
||||||
|
<FormItem label="手机号">
|
||||||
|
<Input v-model:value="formData.Mobile" disabled />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
<FormItem label="产品名称">
|
<FormItem label="产品名称">
|
||||||
<Input v-model:value="formData.ProductName" />
|
<Input v-model:value="formData.ProductName" disabled />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
<FormItem label="价码">
|
<FormItem label="价码">
|
||||||
<Input v-model:value="formData.PriceCode" />
|
<Input v-model:value="formData.PriceCode" disabled />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
<FormItem label="快递号">
|
<FormItem label="快递号">
|
||||||
<Input v-model:value="formData.ExpressNumber" />
|
<Input v-model:value="formData.ExpressNumber" />
|
||||||
|
@ -26,7 +32,7 @@ const formData = ref<OrderEntity>(editorData.formData);
|
||||||
<Status v-model:value="formData.Status" />
|
<Status v-model:value="formData.Status" />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
<FormItem label="备注">
|
<FormItem label="备注">
|
||||||
<Textarea v-model:value="formData.Remark" :auto-size="{ minRows: 3, maxRows: 6 }" />
|
<Textarea v-model:value="formData.Remark" :auto-size="{ minRows: 3, maxRows: 6 }" />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
</Form>
|
</Form>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
|
|
|
@ -5,6 +5,8 @@ import UploadForm from '@/components/content/dialog/uploadForm.vue';
|
||||||
import Grid from './grid.vue';
|
import Grid from './grid.vue';
|
||||||
import Search from './search.vue';
|
import Search from './search.vue';
|
||||||
import { pageData, usePageInit } from './page';
|
import { pageData, usePageInit } from './page';
|
||||||
|
import { beforeFileList, afterUpload, beforeUpload } from './upload';
|
||||||
|
|
||||||
usePageInit();
|
usePageInit();
|
||||||
|
|
||||||
// 定义异步组件
|
// 定义异步组件
|
||||||
|
@ -18,7 +20,11 @@ const Editor = defineAsyncComponent(() => import('./editor.vue'));
|
||||||
<component :is="Editor" v-if="pageData.editor?.visible" />
|
<component :is="Editor" v-if="pageData.editor?.visible" />
|
||||||
<UploadForm
|
<UploadForm
|
||||||
v-if="pageData.subEditor!.uploadForm.visible"
|
v-if="pageData.subEditor!.uploadForm.visible"
|
||||||
|
@before:file-list="beforeFileList"
|
||||||
|
@before:upload="beforeUpload"
|
||||||
|
@after:upload="afterUpload"
|
||||||
width="600px"
|
width="600px"
|
||||||
|
mode="Row"
|
||||||
:upload-form="pageData.subEditor!.uploadForm"
|
:upload-form="pageData.subEditor!.uploadForm"
|
||||||
:max-count="1"
|
:max-count="1"
|
||||||
:page-data="pageData"
|
:page-data="pageData"
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { MinioFile } from '@skyfox2000/webbase';
|
||||||
/**
|
/**
|
||||||
* 订单信息
|
* 订单信息
|
||||||
*/
|
*/
|
||||||
|
@ -6,6 +7,10 @@ export interface OrderEntity {
|
||||||
* 订单ID
|
* 订单ID
|
||||||
*/
|
*/
|
||||||
Id: string | null;
|
Id: string | null;
|
||||||
|
/**
|
||||||
|
* 订单号
|
||||||
|
*/
|
||||||
|
OrderNo: string | null;
|
||||||
/**
|
/**
|
||||||
* 所属会员
|
* 所属会员
|
||||||
*/
|
*/
|
||||||
|
@ -14,6 +19,10 @@ export interface OrderEntity {
|
||||||
* 所属会员
|
* 所属会员
|
||||||
*/
|
*/
|
||||||
MemberName: string | null;
|
MemberName: string | null;
|
||||||
|
/**
|
||||||
|
* 手机号
|
||||||
|
*/
|
||||||
|
Mobile: string | null;
|
||||||
/**
|
/**
|
||||||
* 价码ID
|
* 价码ID
|
||||||
*/
|
*/
|
||||||
|
@ -37,11 +46,11 @@ export interface OrderEntity {
|
||||||
/**
|
/**
|
||||||
* 快递地址信息
|
* 快递地址信息
|
||||||
*/
|
*/
|
||||||
ExpressInfo?: { [key: string]: any };
|
ExpressInfo?: Record;
|
||||||
/**
|
/**
|
||||||
* 检查报告
|
* 检查报告
|
||||||
*/
|
*/
|
||||||
ReportFileUrl?: string | null;
|
ReportFile?: MinioFile[];
|
||||||
/**
|
/**
|
||||||
* 订单状态
|
* 订单状态
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -2,7 +2,15 @@
|
||||||
* 启动配置
|
* 启动配置
|
||||||
* API操作
|
* API操作
|
||||||
*/
|
*/
|
||||||
import { usePageFactory, ApiUrls, ValidateRule, ButtonTool, exportSelectedRows, EditorData } from '@skyfox2000/webbase';
|
import {
|
||||||
|
usePageFactory,
|
||||||
|
ApiUrls,
|
||||||
|
ValidateRule,
|
||||||
|
ButtonTool,
|
||||||
|
exportSelectedRows,
|
||||||
|
isEmpty,
|
||||||
|
PageData,
|
||||||
|
} from '@skyfox2000/webbase';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import message from 'vue-m-message';
|
import message from 'vue-m-message';
|
||||||
|
|
||||||
|
@ -32,12 +40,16 @@ export const OrderUrl: ApiUrls = {
|
||||||
url: '/api/RCOrderSrv/remove',
|
url: '/api/RCOrderSrv/remove',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
update: {
|
||||||
|
url: '/api/RCOrderSrv/update',
|
||||||
|
},
|
||||||
|
|
||||||
upload: {
|
upload: {
|
||||||
url: '',
|
url: '/api/FileSrv/upload',
|
||||||
header: {
|
},
|
||||||
'Content-Type': 'multipart/form-data',
|
|
||||||
},
|
download: {
|
||||||
authorize: true, // 需要授权
|
url: '/api/FileSrv/download',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -47,15 +59,17 @@ export const OrderUrl: ApiUrls = {
|
||||||
*/
|
*/
|
||||||
const defaultData: OrderEntity = {
|
const defaultData: OrderEntity = {
|
||||||
Id: null,
|
Id: null,
|
||||||
|
OrderNo: null,
|
||||||
MemberId: null,
|
MemberId: null,
|
||||||
MemberName: null,
|
MemberName: null,
|
||||||
|
Mobile: null,
|
||||||
PriceId: null,
|
PriceId: null,
|
||||||
PriceCode: null,
|
PriceCode: null,
|
||||||
ProductName: null,
|
ProductName: null,
|
||||||
Address: null,
|
Address: null,
|
||||||
ExpressNumber: null,
|
ExpressNumber: null,
|
||||||
ExpressInfo: {},
|
ExpressInfo: {},
|
||||||
ReportFileUrl: null,
|
ReportFile: [],
|
||||||
Status: null,
|
Status: null,
|
||||||
Remark: null,
|
Remark: null,
|
||||||
Enabled: 1,
|
Enabled: 1,
|
||||||
|
@ -98,25 +112,34 @@ const columns = ref([
|
||||||
{
|
{
|
||||||
title: '订单号',
|
title: '订单号',
|
||||||
dataIndex: 'OrderNo',
|
dataIndex: 'OrderNo',
|
||||||
width: 120,
|
width: 100,
|
||||||
responsive: ['md'],
|
responsive: ['md'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '会员名',
|
title: '会员名',
|
||||||
dataIndex: 'MemberName',
|
dataIndex: 'MemberName',
|
||||||
width: 120,
|
width: 60,
|
||||||
responsive: ['md'],
|
responsive: ['md'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '手机号',
|
title: '手机号',
|
||||||
dataIndex: 'Mobile',
|
dataIndex: 'Mobile',
|
||||||
width: 120,
|
width: 110,
|
||||||
responsive: ['md'],
|
responsive: ['md'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '价码',
|
title: '订单日期',
|
||||||
dataIndex: 'PriceCode',
|
dataIndex: 'PriceCode',
|
||||||
|
width: 90,
|
||||||
|
customRender: ({ record }: { record: OrderEntity }) => {
|
||||||
|
return record.CreateTime!.substring(0, 10);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '产品',
|
||||||
|
dataIndex: 'ProductName',
|
||||||
width: 100,
|
width: 100,
|
||||||
|
ellipsis: true,
|
||||||
responsive: ['lg'],
|
responsive: ['lg'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -129,7 +152,7 @@ const columns = ref([
|
||||||
{
|
{
|
||||||
title: '订单状态',
|
title: '订单状态',
|
||||||
dataIndex: 'Status',
|
dataIndex: 'Status',
|
||||||
width: 100,
|
width: 70,
|
||||||
responsive: ['md'],
|
responsive: ['md'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -146,6 +169,7 @@ gridData.remotePage = false;
|
||||||
gridData.selectKeys = [];
|
gridData.selectKeys = [];
|
||||||
gridData.selectRows = [];
|
gridData.selectRows = [];
|
||||||
gridData.selectable = true;
|
gridData.selectable = true;
|
||||||
|
|
||||||
let download: ButtonTool = {
|
let download: ButtonTool = {
|
||||||
label: '下载',
|
label: '下载',
|
||||||
key: 'download',
|
key: 'download',
|
||||||
|
@ -159,18 +183,8 @@ let download: ButtonTool = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
gridData.buttons = ['New', download];
|
gridData.buttons = [download];
|
||||||
|
import { OrderEntity } from './model';
|
||||||
// 文件上传弹窗
|
|
||||||
let uploadForm: EditorData<OrderEntity> = {
|
|
||||||
visible: false,
|
|
||||||
formData: JSON.parse(JSON.stringify(defaultData)),
|
|
||||||
isFormSaving: false,
|
|
||||||
isFormLoading: false,
|
|
||||||
};
|
|
||||||
pageData.value.subEditor = {
|
|
||||||
uploadForm,
|
|
||||||
};
|
|
||||||
|
|
||||||
gridData.tools = ['Reload', 'Fullscreen'];
|
gridData.tools = ['Reload', 'Fullscreen'];
|
||||||
let upload: ButtonTool = {
|
let upload: ButtonTool = {
|
||||||
|
@ -178,9 +192,44 @@ let upload: ButtonTool = {
|
||||||
key: 'upload',
|
key: 'upload',
|
||||||
type: 'default',
|
type: 'default',
|
||||||
icon: 'icon-upload',
|
icon: 'icon-upload',
|
||||||
click: (_, row) => {
|
visible: (row: OrderEntity) => {
|
||||||
pageData.value.subEditor!.uploadForm.formData = row;
|
if (!row || isEmpty(row.ReportFile)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
click: <T>(_: PageData<T>, row: T) => {
|
||||||
|
const rowData = row as OrderEntity;
|
||||||
|
pageData.value.subEditor!.uploadForm.formData = {
|
||||||
|
Id: rowData.Id,
|
||||||
|
OrderNo: rowData.OrderNo,
|
||||||
|
Mobile: rowData.Mobile,
|
||||||
|
ReportFile: rowData.ReportFile,
|
||||||
|
};
|
||||||
pageData.value.subEditor!.uploadForm.visible = !pageData.value.subEditor!.uploadForm.visible;
|
pageData.value.subEditor!.uploadForm.visible = !pageData.value.subEditor!.uploadForm.visible;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
gridData.operates = [upload, 'Edit', 'Delete'];
|
|
||||||
|
let view: ButtonTool = {
|
||||||
|
label: '查看报告',
|
||||||
|
key: 'view',
|
||||||
|
type: 'default',
|
||||||
|
icon: 'icon-view',
|
||||||
|
visible: (row: OrderEntity) => {
|
||||||
|
if (row && !isEmpty(row.ReportFile)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
click: <T>(_: PageData<T>, row: T) => {
|
||||||
|
const rowData = row as OrderEntity;
|
||||||
|
pageData.value.subEditor!.uploadForm.formData = {
|
||||||
|
Id: rowData.Id,
|
||||||
|
OrderNo: rowData.OrderNo,
|
||||||
|
Mobile: rowData.Mobile,
|
||||||
|
ReportFile: rowData.ReportFile,
|
||||||
|
};
|
||||||
|
pageData.value.subEditor!.uploadForm.visible = !pageData.value.subEditor!.uploadForm.visible;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
gridData.operates = [upload, view, 'Edit', 'Delete'];
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
import { EditorData, isEmpty, MinioFile, path, UploadFile, UploadStatus } from '@skyfox2000/webbase';
|
||||||
|
import { OrderUrl, pageData } from './page';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
|
// 文件上传弹窗
|
||||||
|
let uploadForm: EditorData<Record<string, any>> = {
|
||||||
|
visible: false,
|
||||||
|
formData: {},
|
||||||
|
isFormSaving: false,
|
||||||
|
isFormLoading: false,
|
||||||
|
saveUrl: OrderUrl.urls.update,
|
||||||
|
};
|
||||||
|
|
||||||
|
pageData.value.subEditor = {
|
||||||
|
uploadForm,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const beforeFileList = (editorData: EditorData<OrderEntity>, fileList: UploadFile[]) => {
|
||||||
|
if (!isEmpty(editorData.formData?.ReportFile)) {
|
||||||
|
for (const reportFile of editorData.formData?.ReportFile!) {
|
||||||
|
const minioFile = reportFile as MinioFile;
|
||||||
|
const file: UploadFile = {
|
||||||
|
uid: minioFile.ETag,
|
||||||
|
name: minioFile.Key,
|
||||||
|
fileName: minioFile.FileName!,
|
||||||
|
lastModifiedDate: dayjs(minioFile.UpdateTime).toDate(),
|
||||||
|
status: minioFile.Status ?? UploadStatus.Online,
|
||||||
|
percent: 0,
|
||||||
|
params: {},
|
||||||
|
minioFile: minioFile,
|
||||||
|
};
|
||||||
|
minioFile.Status = file.status!;
|
||||||
|
fileList.push(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const beforeUpload = (files: UploadFile[]) => {
|
||||||
|
files.forEach((file) => {
|
||||||
|
file.name = path.join(
|
||||||
|
'/Order/ReportFile',
|
||||||
|
uploadForm.formData.Mobile,
|
||||||
|
uploadForm.formData.OrderNo,
|
||||||
|
file.fileName!,
|
||||||
|
);
|
||||||
|
file.params = {
|
||||||
|
FileKey: file.name,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const afterUpload = (files: UploadFile[]) => {
|
||||||
|
const uploadFiles: Record<string, any>[] = [];
|
||||||
|
files.forEach((file) => {
|
||||||
|
if (
|
||||||
|
(file.status == UploadStatus.Success ||
|
||||||
|
file.status == UploadStatus.Online ||
|
||||||
|
file.status == UploadStatus.Offline) &&
|
||||||
|
file.minioFile
|
||||||
|
) {
|
||||||
|
file.minioFile.FileName = file.fileName!;
|
||||||
|
uploadFiles.push(file.minioFile);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
/// 为空的话,即删除所有上传的文件
|
||||||
|
uploadForm.formData!.ReportFile = uploadFiles;
|
||||||
|
};
|
|
@ -24,6 +24,12 @@ export const PriceQRUrl: ApiUrls = {
|
||||||
save: {
|
save: {
|
||||||
url: '/api/RCPriceQRSrv/save',
|
url: '/api/RCPriceQRSrv/save',
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* 更新地址
|
||||||
|
*/
|
||||||
|
update: {
|
||||||
|
url: '/api/RCPriceQRSrv/update',
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* 删除地址
|
* 删除地址
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -24,6 +24,12 @@ export const AccountUrl: ApiUrls = {
|
||||||
save: {
|
save: {
|
||||||
url: '/api/RCAccountOpSrv/save',
|
url: '/api/RCAccountOpSrv/save',
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* 更新地址
|
||||||
|
*/
|
||||||
|
update: {
|
||||||
|
url: '/api/RCAccountOpSrv/update',
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* 删除地址
|
* 删除地址
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -28,6 +28,12 @@ export const DoctorUrl: ApiUrls = {
|
||||||
save: {
|
save: {
|
||||||
url: '/api/RCDoctorSrv/save',
|
url: '/api/RCDoctorSrv/save',
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* 更新地址
|
||||||
|
*/
|
||||||
|
update: {
|
||||||
|
url: '/api/RCDoctorSrv/update',
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* 删除地址
|
* 删除地址
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue