feat: 添加原料库上传功能和相关组件
- 在 `raw-material` 组件中添加上传按钮和抽屉组件 - 新增 `add-raw-material-drawer` 组件及其样式文件 - 更新样式文件以支持新的上传界面 - 调整 Ant Select 和 Drawer 组件的样式
This commit is contained in:
20
src/styles/components/ant-drawer.scss
Normal file
20
src/styles/components/ant-drawer.scss
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
.ant-drawer {
|
||||||
|
.ant-drawer-header {
|
||||||
|
.ant-drawer-header-title {
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.ant-drawer-close {
|
||||||
|
order: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-drawer-title {
|
||||||
|
color: #211f24;
|
||||||
|
font-family: $font-family-medium;
|
||||||
|
font-size: 18px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 26px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -36,7 +36,6 @@
|
|||||||
border-color: $color-error !important;
|
border-color: $color-error !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-select {
|
.ant-select {
|
||||||
@ -103,20 +102,69 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.ant-select-single {
|
||||||
|
.ant-select-selector {
|
||||||
|
height: 32px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.ant-select-lg {
|
||||||
|
.ant-select-selector {
|
||||||
|
height: 36px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.ant-select-sm {
|
||||||
|
.ant-select-selector {
|
||||||
|
height: 28px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-select.ant-select-single {
|
.ant-select-dropdown {
|
||||||
.ant-select-selector {
|
padding: 4px 0;
|
||||||
height: 32px !important;
|
|
||||||
}
|
.ant-select-item-option {
|
||||||
&.ant-select-lg {
|
padding: 0 12px;
|
||||||
.ant-select-selector {
|
height: 36px;
|
||||||
height: 36px !important;
|
align-items: center;
|
||||||
|
|
||||||
|
.ant-select-item-option-state {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
&.ant-select-sm {
|
&:not(.ant-select-item-option-disabled) {
|
||||||
.ant-select-selector {
|
&:hover {
|
||||||
height: 28px !important;
|
background-color: #F2F3F5 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-select-item-option-content {
|
||||||
|
color: #211F24;
|
||||||
|
font-family: $font-family-regular;
|
||||||
|
font-size: 14px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.ant-select-item-option-selected {
|
||||||
|
background-color: transparent !important;
|
||||||
|
color: #6D4CFE !important;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #F2F3F5 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-select-item-option-content {
|
||||||
|
color: #6D4CFE;
|
||||||
|
font-weight: 500;
|
||||||
|
font-family: $font-family-medium;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
&.ant-select-item-option-active {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,4 +2,18 @@
|
|||||||
.ant-input {
|
.ant-input {
|
||||||
padding: 8px 12px 4px 12px;
|
padding: 8px 12px 4px 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.ant-input-textarea-show-count {
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
right: 8px;
|
||||||
|
bottom: 4px;
|
||||||
|
font-family: $font-family-regular;
|
||||||
|
color: #939499;
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,4 +26,5 @@
|
|||||||
@import "./ant-tag.scss";
|
@import "./ant-tag.scss";
|
||||||
@import "./ant-switch.scss";
|
@import "./ant-switch.scss";
|
||||||
@import "./ant-step.scss";
|
@import "./ant-step.scss";
|
||||||
@import "./ant-spin.scss";
|
@import "./ant-spin.scss";
|
||||||
|
@import "./ant-drawer.scss";
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
|
|
||||||
export function toFixed(num: number | string, n: number): number {
|
export function toFixed(num: number | string, n: number): number {
|
||||||
return parseFloat(parseFloat(num.toString()).toFixed(n));
|
return parseFloat(parseFloat(num.toString()).toFixed(n));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,12 +43,12 @@
|
|||||||
<img :src="visible ? icon2 : icon1" width="20" height="20" class="cursor-pointer" />
|
<img :src="visible ? icon2 : icon1" width="20" height="20" class="cursor-pointer" />
|
||||||
</template>
|
</template>
|
||||||
</Input.Password>
|
</Input.Password>
|
||||||
<p class="color-#F64B31 text-12px font-400 lh-20px font-family-regular" v-show="errMsg">
|
<p v-show="errMsg" class="color-#F64B31 h-20px text-12px font-400 lh-20px font-family-regular">
|
||||||
{{ errMsg }}
|
{{ errMsg }}
|
||||||
</p>
|
</p>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
|
|
||||||
<FormItem class="mt-52px">
|
<FormItem class="mt-32px">
|
||||||
<div class="text-12px flex justify-center items-center mb-16px">
|
<div class="text-12px flex justify-center items-center mb-16px">
|
||||||
<Checkbox v-model:checked="hasCheck" class="mr-8px"></Checkbox>
|
<Checkbox v-model:checked="hasCheck" class="mr-8px"></Checkbox>
|
||||||
<span class="text-12px color-#737478 font-400 lh-20px font-family-regular"
|
<span class="text-12px color-#737478 font-400 lh-20px font-family-regular"
|
||||||
@ -67,14 +67,18 @@
|
|||||||
登录
|
登录
|
||||||
</Button>
|
</Button>
|
||||||
<div class="flex justify-between btn-row">
|
<div class="flex justify-between btn-row">
|
||||||
<Button
|
<div>
|
||||||
type="text"
|
<Button
|
||||||
class="!color-#939499 !p-0 !h-22px hover:color-#6D4CFE"
|
v-show="!isCaptchaLogin"
|
||||||
size="small"
|
class="!color-#939499 !p-0 !h-22px hover:color-#6D4CFE"
|
||||||
@click="onForgetPassword"
|
size="small"
|
||||||
>
|
type="text"
|
||||||
忘记密码?
|
@click="onForgetPassword"
|
||||||
</Button>
|
>
|
||||||
|
忘记密码?
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
type="text"
|
type="text"
|
||||||
class="!color-#939499 !p-0 !h-22px hover:color-#6D4CFE"
|
class="!color-#939499 !p-0 !h-22px hover:color-#6D4CFE"
|
||||||
|
|||||||
@ -0,0 +1,244 @@
|
|||||||
|
<script lang="tsx">
|
||||||
|
import { Drawer, Button, Upload, Table, Input } from 'ant-design-vue';
|
||||||
|
|
||||||
|
const { Column } = Table;
|
||||||
|
const { TextArea } = Input;
|
||||||
|
|
||||||
|
import CommonSelect from '@/components/common-select';
|
||||||
|
import ImgLazyLoad from '@/components/img-lazy-load';
|
||||||
|
|
||||||
|
import { formatFileSize, getVideoInfo, formatDuration, formatUploadSpeed } from '@/utils/tools';
|
||||||
|
import { getRawMaterialTagsList } from '@/api/all/generationWorkshop';
|
||||||
|
|
||||||
|
import icon1 from '@/assets/img/media-account/icon-delete.png';
|
||||||
|
|
||||||
|
const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp'];
|
||||||
|
const videoExtensions = ['.mp4', '.mov', '.avi', '.flv', '.wmv', '.m4v'];
|
||||||
|
const documentExtensions = ['.txt', '.doc', '.docx', '.pdf', '.xls', '.xlsx'];
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
setup(_, { attrs, slots, expose }) {
|
||||||
|
const visible = ref(false);
|
||||||
|
const submitLoading = ref(false);
|
||||||
|
const uploadData = ref([]);
|
||||||
|
const tagData = ref([]);
|
||||||
|
|
||||||
|
const checkSuccessNum = computed(() => {
|
||||||
|
return uploadData.value.filter((item) => item.status === 'success').length;
|
||||||
|
});
|
||||||
|
|
||||||
|
const getTagData = async () => {
|
||||||
|
const { code, data } = await getRawMaterialTagsList();
|
||||||
|
if (code === 200) {
|
||||||
|
tagData.value = data ?? [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const open = () => {
|
||||||
|
getTagData();
|
||||||
|
visible.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onClose = () => {
|
||||||
|
visible.value = false;
|
||||||
|
|
||||||
|
uploadData.value = [];
|
||||||
|
tagData.value = [];
|
||||||
|
submitLoading.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleUpload = async (option) => {
|
||||||
|
// console.log('handleUpload', option);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getFileType = (fileName) => {
|
||||||
|
const ext = fileName.slice(fileName.lastIndexOf('.')).toLowerCase();
|
||||||
|
|
||||||
|
if (imageExtensions.includes(ext)) {
|
||||||
|
return '图片';
|
||||||
|
} else if (videoExtensions.includes(ext)) {
|
||||||
|
return '视频';
|
||||||
|
} else if (documentExtensions.includes(ext)) {
|
||||||
|
return '文档';
|
||||||
|
} else {
|
||||||
|
return '其他';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onConfirm = () => {
|
||||||
|
console.log('onConfirm');
|
||||||
|
};
|
||||||
|
const handleDelete = (file) => {
|
||||||
|
uploadData.value = uploadData.value.filter((item) => item.uid !== file.uid);
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderUploadList = (file, actions) => {
|
||||||
|
if (!uploadData.value.length) return null;
|
||||||
|
|
||||||
|
console.log('renderUploadList', uploadData.value);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p class="cts !color-#939499 mb-10px">
|
||||||
|
已上传:<span class="!color-#211F24">{`${checkSuccessNum.value}/${uploadData.value.length}`}</span>
|
||||||
|
</p>
|
||||||
|
<Table ref="tableRef" dataSource={uploadData.value} pagination={false} class="manuscript-table w-100% flex-1">
|
||||||
|
<Column
|
||||||
|
title="文件名称"
|
||||||
|
dataIndex="name"
|
||||||
|
key="name"
|
||||||
|
width={347}
|
||||||
|
ellipsis={true}
|
||||||
|
customRender={({ text, record }) => {
|
||||||
|
return (
|
||||||
|
<div class="flex items-center">
|
||||||
|
<ImgLazyLoad width={64} height={64} src={record.cover} class="!rounded-6px mr-16px flex-shrink-0" />
|
||||||
|
|
||||||
|
<TextArea
|
||||||
|
v-model:value={record.name}
|
||||||
|
placeholder="请输入文件名称"
|
||||||
|
size="large"
|
||||||
|
class="w-full !h-72px"
|
||||||
|
showCount
|
||||||
|
maxlength={20}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Column
|
||||||
|
title="上传状态"
|
||||||
|
dataIndex="status"
|
||||||
|
key="status"
|
||||||
|
width={164}
|
||||||
|
customRender={({ text, record }) => {
|
||||||
|
if (record.status === 'done') {
|
||||||
|
return <span class="upload-text">上传成功</span>;
|
||||||
|
} else if (record.status === 'error') {
|
||||||
|
return <span class="upload-text">上传失败</span>;
|
||||||
|
} else {
|
||||||
|
return <span class="upload-text">上传中</span>;
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Column
|
||||||
|
title="标签"
|
||||||
|
dataIndex="tags"
|
||||||
|
key="tags"
|
||||||
|
width={243}
|
||||||
|
customRender={({ text, record }) => {
|
||||||
|
return (
|
||||||
|
<CommonSelect
|
||||||
|
v-model={record.tags}
|
||||||
|
class="w-full"
|
||||||
|
multiple
|
||||||
|
options={tagData}
|
||||||
|
placeholder="请选择标签"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Column
|
||||||
|
title="类型"
|
||||||
|
dataIndex="type"
|
||||||
|
key="type"
|
||||||
|
width={80}
|
||||||
|
customRender={({ text, record }) => {
|
||||||
|
const fileName = record.name || '';
|
||||||
|
return <span>{getFileType(fileName)}</span>;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Column
|
||||||
|
title="大小"
|
||||||
|
dataIndex="size"
|
||||||
|
key="size"
|
||||||
|
width={100}
|
||||||
|
customRender={({ text, record }) => formatFileSize(record.size)}
|
||||||
|
/>
|
||||||
|
<Column
|
||||||
|
title="操作"
|
||||||
|
key="action"
|
||||||
|
width={118}
|
||||||
|
fixed="right"
|
||||||
|
customRender={({ text, record }) => {
|
||||||
|
return (
|
||||||
|
<div class="flex items-center">
|
||||||
|
<Button type="text" class="!h-22px !p-0 mr-16px">
|
||||||
|
取消生成
|
||||||
|
</Button>
|
||||||
|
<img
|
||||||
|
class="cursor-pointer"
|
||||||
|
src={icon1}
|
||||||
|
width="14"
|
||||||
|
height="14"
|
||||||
|
onClick={() => handleDelete(record)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Table>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
expose({
|
||||||
|
open,
|
||||||
|
});
|
||||||
|
return () => (
|
||||||
|
<Drawer
|
||||||
|
width={1100}
|
||||||
|
title="上传到原料库"
|
||||||
|
rootClassName="xt-add-raw-material-modal"
|
||||||
|
v-model:open={visible.value}
|
||||||
|
onClose={onClose}
|
||||||
|
>
|
||||||
|
<section class="content flex-1 pt-8px px-24px pb-24px">
|
||||||
|
<div class=" rounded-16px bg-#F7F8FA p-16px flex flex-col items-center mb-24px">
|
||||||
|
<Upload
|
||||||
|
v-model:file-list={uploadData.value}
|
||||||
|
action="/"
|
||||||
|
multiple
|
||||||
|
customRequest={handleUpload}
|
||||||
|
class="w-full mb-16px"
|
||||||
|
accept={[...imageExtensions, ...videoExtensions, ...documentExtensions].join(',')}
|
||||||
|
showUploadList={false}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="upload-box rounded-8px cursor-pointer h-100px w-full border border-dashed border-#D7D7D9 flex flex-col items-center justify-center w-full">
|
||||||
|
<icon-plus size="14" class="mb-10px color-#55585F" />
|
||||||
|
<span class="cts">点击或拖拽文件到此处上传</span>
|
||||||
|
</div>
|
||||||
|
</Upload>
|
||||||
|
<p class="mb-4px cts !color-#939499 !text-12px !lh-20px">{`视频格式:视频格式:MP4、AVI、MOV,大小<1000MB`}</p>
|
||||||
|
<p
|
||||||
|
class="mb-4px cts !color-#939499 !text-12px !lh-20px">{`图片格式:PNG、JPG、JPEG、GIF、WEBP、BMP,大小<20MB`}</p>
|
||||||
|
<p class="cts !color-#939499 !text-12px !lh-20px">{`文本格式:TXT、DOC、DOCX、PDF,大小<20MB`}</p>
|
||||||
|
</div>
|
||||||
|
{renderUploadList()}
|
||||||
|
</section>
|
||||||
|
<footer class="footer h-68px px-24px flex items-center justify-end">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<Button size="large" onClick={onClose} class="mr-12px">
|
||||||
|
取消
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
size="large"
|
||||||
|
type="primary"
|
||||||
|
onClick={onConfirm}
|
||||||
|
loading={submitLoading.value}
|
||||||
|
disabled={!checkSuccessNum.value}
|
||||||
|
>
|
||||||
|
确定
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</Drawer>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import './style.scss';
|
||||||
|
</style>
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
.xt-add-raw-material-modal {
|
||||||
|
.ant-drawer-header {
|
||||||
|
height: 58px;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-upload {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-drawer-body {
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.cts {
|
||||||
|
color: #211f24;
|
||||||
|
font-family: $font-family-regular;
|
||||||
|
font-size: 14px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
.upload-box {
|
||||||
|
transition: all 0.3s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: #6d4cfe;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-text {
|
||||||
|
color: #000;
|
||||||
|
text-align: center;
|
||||||
|
font-family: $font-family-regular;
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,6 +7,7 @@ import FilterBlock from './components/filter-block/index.vue';
|
|||||||
import RawMaterialTable from './components/table/index.vue';
|
import RawMaterialTable from './components/table/index.vue';
|
||||||
import DeleteRawMaterialModal from './components/table/delete-file-modal.vue';
|
import DeleteRawMaterialModal from './components/table/delete-file-modal.vue';
|
||||||
import TagsManageModal from './components/tags-manage-modal';
|
import TagsManageModal from './components/tags-manage-modal';
|
||||||
|
import AddRawMaterialDrawer from './components/add-raw-material-drawer';
|
||||||
|
|
||||||
import { useTableSelectionWithPagination } from '@/hooks/useTableSelectionWithPagination';
|
import { useTableSelectionWithPagination } from '@/hooks/useTableSelectionWithPagination';
|
||||||
import { getRawMaterialsPage } from '@/api/all/generationWorkshop';
|
import { getRawMaterialsPage } from '@/api/all/generationWorkshop';
|
||||||
@ -32,6 +33,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
const deleteRawMaterialModalRef = ref(null);
|
const deleteRawMaterialModalRef = ref(null);
|
||||||
const tagsManageModalRef = ref(null);
|
const tagsManageModalRef = ref(null);
|
||||||
|
const addRawMaterialDrawerRef = ref(null);
|
||||||
|
|
||||||
const query = ref(cloneDeep(INITIAL_QUERY));
|
const query = ref(cloneDeep(INITIAL_QUERY));
|
||||||
const handleSearch = () => {
|
const handleSearch = () => {
|
||||||
@ -91,7 +93,7 @@ export default defineComponent({
|
|||||||
tagsManageModalRef.value?.open();
|
tagsManageModalRef.value?.open();
|
||||||
};
|
};
|
||||||
const handleAddMaterial = () => {
|
const handleAddMaterial = () => {
|
||||||
console.log('handleAddMaterial');
|
addRawMaterialDrawerRef.value?.open();
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@ -182,6 +184,7 @@ export default defineComponent({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<TagsManageModal ref={tagsManageModalRef} />
|
<TagsManageModal ref={tagsManageModalRef} />
|
||||||
|
<AddRawMaterialDrawer ref={addRawMaterialDrawerRef} />
|
||||||
<DeleteRawMaterialModal ref={deleteRawMaterialModalRef} onBatchUpdate={onBatchSuccess} onUpdate={getData} />
|
<DeleteRawMaterialModal ref={deleteRawMaterialModalRef} onBatchUpdate={onBatchSuccess} onUpdate={getData} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user