123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694 |
- import getMD5 from '@/components/MD5';
- import { useAjax } from '@/Hook/useAjax';
- import {
- bdSysMediaList,
- bdSysMediaAdd,
- delMedia,
- bdSysMediaEdit,
- getFileUrl,
- getMedia,
- configSortApi,
- getFolderTree,
- editMediaFolder,
- bdSysMediaAddsApi,
- } from '@/services/launchAdq/material';
- import { blobToBase64, dataURLtoFile, videoMessage } from '@/utils/compress';
- import { getImgSize } from '@/utils/utils';
- import { message } from 'antd';
- import { compressAccurately } from 'image-conversion';
- import { Dispatch, useCallback, useReducer, useState } from 'react';
- import { request } from 'umi';
- /**新本地素材弹窗 */
- type State = {
- fileVisible?: boolean; //文件夹弹窗
- imgVisrible?: boolean; //img,voice,video弹窗
- imgsVisrible?: boolean,//
- newsVisrible?: boolean; //news弹窗
- knewsVisrible?: boolean; //客服图文弹窗
- fileName?: string; //文件夹名称
- sort?: number; // 排序
- videoTitle?: string; //video文件名称
- videoDescription?: string; //视频描述
- belongUser?: any; //0公共本地|1个人本地
- mediaType?: 'VIDEO' | 'IMG' | 'PAGE'; // 类型
- parentId?: any; //上级目录ID,顶级使用null
- url?: string; //素材地址
- pathId?: string; //路径ID
- selectFile?: number[]; //选中的文件列表
- rightClickPup?: any; // /**右键菜单开关 all为全部 id 为目标文件 空为不显示*/
- xy?: { x: number; y: number }; // /**鼠标位置 菜单弹窗位置使用*/
- delPupId?: any; //按了单个删除存放的id为了让弹窗区分文件
- actionItem?: any; //当前选中的Itme
- path?: any[]; //个人路径
- publicPath?: any[]; //本地路径
- file?: File; //素材文件
- selectItem?: any[]; //单选素材时存放选中的素材
- knewsdefaultData?: any; //k图文编辑时的默认内容
- sortVisible?: boolean; //排序弹窗
- num?: number; //选择数量
- size?: number; // 需要上传素材的大小
- upLoadLoading?: boolean;
- cloudSize?: any[];
- maxSize?: number; //素材最大尺寸
- adcreativeTemplateId?: number; //创意模板 id
- promotedObjectType?: string; //推广目标类型
- promotedObjectId?: string; //推广目标 id
- pageType?: string; //落地页类型
- canvasType?: string; //原生页类型
- siteSet?: string[]; //版位
- sourceType?: string; //视频/图片/原生页等素材的创建来源类型
- marketingScene?: string; //营销场景
- };
- export type Action = {
- type: 'set' | 'init';
- params?: any;
- };
- const typeEnum = {
- IMG: '图片',
- VIDEO: '视频',
- };
- function reducer(state: State, action: Action) {
- let { type, params } = action;
- let newState = JSON.parse(JSON.stringify(state));
- newState.file = state.file;
- switch (type) {
- case 'set':
- Object.keys(params as State).forEach((key: string) => {
- newState[key] = (params as State)[key];
- });
- return newState;
- case 'init':
- return { ...initData, ...params };
- default:
- return state;
- }
- }
- const initData: State = {
- fileVisible: false,
- knewsVisrible: false,
- videoTitle: '',
- videoDescription: '',
- fileName: '',
- belongUser: '1',
- mediaType: 'IMG',
- parentId: null,
- selectFile: [],
- delPupId: '',
- rightClickPup: { id: '' },
- publicPath: [{ title: '公共本地', number: '0' }],
- path: [{ title: '个人本地', number: '0' }],
- imgVisrible: false,
- imgsVisrible: false,
- newsVisrible: false,
- sortVisible: false,
- sort: 0,
- num: 1,
- };
- /**本地素材管理器 */
- function useBdMediaPup() {
- const [state, dispatch]: [State, Dispatch<Action>] = useReducer(reducer, initData);
- const {
- fileName,
- sort,
- belongUser,
- mediaType,
- parentId,
- selectFile,
- selectItem,
- delPupId,
- cloudSize,
- num,
- rightClickPup,
- actionItem,
- path,
- publicPath,
- videoTitle,
- videoDescription,
- size,
- maxSize,
- adcreativeTemplateId,
- promotedObjectType,
- promotedObjectId,
- pageType,
- canvasType,
- siteSet,
- sourceType,
- marketingScene,
- } = state;
- const list = useAjax((params) => bdSysMediaList(params));
- const add = useAjax((params) => bdSysMediaAdd(params), { msgNmae: '新增' });
- const del = useAjax((params) => delMedia(params), { msgNmae: '删除' });
- const edit = useAjax((params) => bdSysMediaEdit(params), { msgNmae: '编辑' });
- const configSort = useAjax((params) => configSortApi(params), { msgNmae: '排序' });
- const adds = useAjax((params) => bdSysMediaAddsApi(params), { msgNmae: '新增' })
- const get = useAjax((params) => getMedia(params)); //获取图文详情
- const get_folder_tree = useAjax((params: any) => getFolderTree(params));
- const edit_media_folder = useAjax((params: any) => editMediaFolder(params));
- const [isOk, setIsOk] = useState<boolean>(true);
- //请求上传地址
- const fileUrl = useAjax(
- (params: { type: string; fileType: 'video' | 'image' }) => getFileUrl(params),
- {
- manual: true,
- },
- );
- /**初始化数据 */
- const init = useCallback((params: State) => {
- console.log('params======>', params);
- dispatch({ type: 'init', params });
- }, []);
- /**设置state */
- const set = useCallback((params: State) => {
- if (params) {
- dispatch({ type: 'set', params });
- }
- }, []);
- /**新增文件夹 */
- const addFolder = () => {
- if (fileName) {
- let obj = {
- title: fileName,
- mediaType,
- folder: true,
- parentId,
- belongUser: belongUser === '0' ? false : true,
- sort,
- };
- add.run(obj).then((res) => {
- get_folder_tree.refresh();
- list.refresh();
- offEditFile(); //关闭弹窗并清空相关数据
- });
- }
- };
- /** 新增图片 视频 */
- const addFile = async (data: any) => {
- if (data) {
- //存在代表素材
- if (!data) {
- return;
- }
- if (data?.file) {
- let file = data.file;
- let fileSize = size || 0;
- if (!size) {
- if (mediaType === 'IMG') {
- fileSize = 307200;
- } else {
- fileSize = 104857600;
- }
- }
- if (mediaType === 'IMG') {
- if (file?.size > fileSize) {
- // 大于300kb进入压缩
- let bole = await compressAccurately(file, 250);
- if (bole?.size > 300000) {
- bole = await compressAccurately(file, 200);
- }
- if (bole?.size > 300000) {
- bole = await compressAccurately(file, 150);
- }
- if (bole?.size > 300000) {
- bole = await compressAccurately(file, 100);
- }
- let newFile = await blobToBase64(bole);
- message.warning({
- content: `选择的图片大于${fileSize / 1024}KB,图片已压缩`,
- duration: 3,
- });
- file = await dataURLtoFile(newFile, file?.name);
- }
- } else if (mediaType === 'VIDEO') {
- if (file?.size > fileSize) {
- // 大于100mb进入压缩
- message.error({
- content: `选择的视频大于${fileSize / 1024 / 1024}MB,请重新选择提交`,
- duration: 3,
- });
- return;
- }
- }
- set({ upLoadLoading: true });
- let width = 0;
- let height = 0;
- if (mediaType === 'IMG') {
- let imgData = await getImgSize(file);
- width = imgData.width;
- height = imgData.height;
- } else if (mediaType === 'VIDEO') {
- let videoInfo: any = await videoMessage([file]);
- width = videoInfo[0].width;
- height = videoInfo[0].height;
- }
- /**修改文件名以用户设置的文件title命名*/
- let newFile = new File(
- [file],
- data?.title ? data?.title + '.' + file?.name?.split('.')[1] : file?.name,
- { type: file?.type },
- );
- let formData = new FormData();
- /**向阿里云请求上传地址*/
- fileUrl
- .run({ type: newFile.type, fileType: mediaType === 'VIDEO' ? 'video' : 'image' })
- .then((res1) => {
- Object.keys(res1).forEach((key: string) => {
- if (key !== 'url') {
- formData.append(key, res1[key]);
- }
- });
- formData.append('file', newFile);
- /**向阿里云返回的上传地址上传文件*/
- request(res1?.ossUrl, { method: 'post', body: formData })
- .then(async (res2: { code: number; data: { url: string } }) => {
- if (res2.code === 200) {
- message.success('上传成功');
- if (data) {
- /**取到返回的文件地址向后端发送具体数据*/
- if (res2?.data?.url) {
- let fileMd5 = await getMD5(newFile);
- let obj = {
- title: data.title,
- mediaType,
- folder: false,
- parentId,
- width,
- height,
- fileMd5,
- belongUser: belongUser === '0' ? false : true,
- url: res2?.data?.url,
- sort: data?.sort,
- fileSize: newFile?.size,
- fileMime: newFile.type,
- };
- if (mediaType === 'VIDEO') {
- obj['videoTitle'] = data?.videoTitle || data?.title;
- obj['videoDescription'] = data?.videoDescription;
- }
- if (!obj?.title) {
- obj.title = data.file.name
- }
- if (obj.title.match(RegExp(/[<>&\\'"/\x08\x09\x0A\x0D\x7F]/g))) {
- obj.title = obj.title.replace(RegExp(/[<>&\\'"/\x08\x09\x0A\x0D\x7F]/g), '')
- }
- obj.title = obj.title.replace(/\.(jpg|jpeg|gif|png)$/i, '')
- add.run(obj).then((res) => {
- list.refresh();
- offEditFile(); //关闭弹窗并清空相关数据
- set({ upLoadLoading: false });
- }).catch(() => set({ upLoadLoading: false }));
- }
- }
- } else {
- message.error('上传失败!');
- }
- })
- .catch(() => set({ upLoadLoading: false }));
- })
- .catch(() => set({ upLoadLoading: false }));
- }
- }
- };
- /** 批量新增图片 视频 */
- const addFiles = async (data: any) => {
- if (data) {//存在代表素材
- if (!data) {
- return
- }
- let { files, ...value } = data
- let params = files?.map(async (item: any, index: number) => {
- let file = item
- let fileSize = size || 0
- if (mediaType === 'IMG') {
- fileSize = value?.fileSize ? value?.fileSize * 1024 : 307200
- } else {
- fileSize = 104857600
- }
- if (mediaType === 'IMG') {
- let bad = 50
- let size = fileSize / 1024
- if (size > 10 && size <= 50) {
- bad = 5
- } else if (size > 50 && size <= 100) {
- bad = 10
- } else if (size > 100 && size <= 300) {
- bad = 20
- } else {
- bad = 50
- }
- if (file?.size > fileSize) { // 大于300kb进入压缩
- let bole = await compressAccurately(file, fileSize / 1024 - bad)
- if (bole?.size > fileSize) {
- bole = await compressAccurately(file, fileSize / 1024 - bad * 2)
- }
- if (bole?.size > fileSize) {
- bole = await compressAccurately(file, fileSize / 1024 - bad * 3)
- }
- if (bole?.size > fileSize) {
- bole = await compressAccurately(file, fileSize / 1024 - bad * 4)
- }
- let newFile = await blobToBase64(bole)
- message.warning({
- content: `选择的图片大于${fileSize / 1024}KB,图片已压缩`,
- duration: 3
- })
- file = await dataURLtoFile(newFile, file?.name)
- }
- } else if (mediaType === 'VIDEO') {
- if (file?.size > fileSize) { // 大于100mb进入压缩
- message.error({
- content: `选择的视频大于${fileSize / 1024 / 1024}MB,请重新选择提交`,
- duration: 3
- })
- return
- }
- }
- let width = 0
- let height = 0
- if (mediaType === 'IMG') {
- let imgData = await getImgSize(file)
- width = imgData.width
- height = imgData.height
- } else if (mediaType === "VIDEO") {
- let videoInfo: any = await videoMessage([file])
- width = videoInfo[0].width
- height = videoInfo[0].height
- }
- /**修改文件名以用户设置的文件title命名*/
- let newFile = new File([file], data?.title ? data?.title + index + 1 + '.' + file?.name?.split('.')[1] : file?.name, { type: file?.type })
- let formData = new FormData();
- set({ upLoadLoading: true })
- let res = await getFileUrl({ type: newFile.type, fileType: mediaType === 'VIDEO' ? 'video' : 'image' }).catch(() => set({ upLoadLoading: false }))
- let res1 = res.data
- Object.keys(res1).forEach((key: string) => {
- if (key !== 'url') {
- formData.append(key, res1[key])
- }
- })
- formData.append('file', newFile)
- /**向阿里云返回的上传地址上传文件*/
- let data1: { code: number, data: { url: string } } = await request(res1?.ossUrl, { method: 'post', body: formData }).catch(() => set({ upLoadLoading: false }))
- message.success('上传成功')
- let fileMd5 = await getMD5(newFile)
- let obj = { title: data.title + (index + 1).toString(), folder: false, parentId, width, height, fileMd5, url: data1?.data?.url, sort: data?.sort, fileSize: newFile?.size, fileMime: newFile.type }
- if (mediaType === 'VIDEO') {
- obj['videoTitle'] = data?.videoTitle || data?.title
- obj['videoDescription'] = data?.videoDescription
- }
- return { ...obj }
- })
- Promise.all(params).then(res => {
- adds.run({ belongUser: belongUser === '0' ? false : true, data: res }).then(response => {
- list.refresh()
- offEditFile()//关闭弹窗并清空相关数据
- set({ upLoadLoading: false })
- }).catch(() => set({ upLoadLoading: false }))
- })
- }
- }
- /**编辑非图文素材名称*/
- const nameOk = useCallback((selectWx: any) => {
- if (fileName && actionItem) {
- let obj = {
- title: fileName,
- belongUser: belongUser === '0' ? false : true,
- sysMediaId: actionItem?.id,
- mediaType: actionItem?.mediaType,
- folder: actionItem?.folder,
- url: actionItem?.url,
- sort,
- };
- // if (mediaType === 'VIDEO') {
- // obj['videoTitle'] = videoTitle;
- // obj['videoDescription'] = videoDescription;
- // }
- edit.run(obj).then((res) => {
- list.refresh();
- get_folder_tree.refresh()
- offEditFile(); //关闭弹窗并清空相关数据
- });
- }
- },
- [fileName, actionItem, edit, belongUser, mediaType, videoTitle, videoDescription],
- );
- /**删除文件 */
- const dels = useCallback((id?: any) => {
- let arr = typeof id === 'number' ? [id] : selectFile;
- let len = arr?.length || 0;
- if (len) {
- arr?.map((id, index) => {
- del.run({ sysMediaId: id, mediaType }).then(() => {
- set({ selectFile: selectFile?.filter((i) => i !== id) }); //清理已删除文件
- if (index === len - 1) {
- list.refresh();
- get_folder_tree.refresh();
- }
- });
- });
- } else {
- message.error('请选择文件')
- }
- },
- [list, selectFile, mediaType],
- );
- /**获取本地素材数据列表 */
- const getList = useCallback(
- (props?: any) => {
- console.log('getList====>', props);
- let obj = {
- pageSize: 30,
- pageNum: 1,
- belongUser: belongUser === '0' ? false : true,
- mediaType,
- parentId,
- sizeQueries: cloudSize,
- maxSize,
- ...props,
- };
- if (mediaType === 'PAGE') {
- obj = {
- ...obj,
- adcreativeTemplateId,
- promotedObjectType,
- promotedObjectId,
- pageType,
- canvasType,
- siteSet,
- sourceType,
- marketingScene,
- };
- }
- list.run(obj).then((res) => {
- setIsOk(true);
- });
- },
- [list, mediaType, belongUser, parentId, cloudSize, maxSize, adcreativeTemplateId, promotedObjectType, promotedObjectId, pageType, canvasType, siteSet, sourceType, marketingScene],
- );
- /**选中文件 single 开启可单选为了在右键删除选择时只选一个*/
- const onFile = useCallback(
- (e: any, item: { id: any; folder?: boolean }, isAll?: boolean, single?: boolean) => {
- let { id } = item;
- e?.stopPropagation();
- if (isAll && !single) {
- set({ selectFile: [...new Set([...(selectFile as number[]), id])] });
- } else {
- if (item?.folder && !single) {
- //假如是文件不让选择
- message.error('不能选择文件夹');
- return;
- }
- set({ selectFile: [item.id], selectItem: [item] });
- }
- },
- [selectFile],
- );
- /**点击文件夹 */
- const fileClick = useCallback(
- (item) => {
- if (isOk) {
- setIsOk(false);
- if (belongUser == '1' && path) {
- set({ path: [...path, item] });
- }
- if (belongUser == '0' && publicPath) {
- set({ publicPath: [...publicPath, item] });
- }
- set({ parentId: item.id });
- getList({ parentId: item.id }); //请求对应文件夹列表
- }
- },
- [path, publicPath, mediaType, belongUser, isOk],
- );
- /**点击目录树*/
- const treeClick = useCallback(
- (item) => {
- if (isOk) {
- setIsOk(false);
- console.log(item, belongUser == '1');
- if (belongUser == '1' && path) {
- set({ path: [path[0], item] });
- }
- if (belongUser == '0' && publicPath) {
- set({ publicPath: [publicPath[0], item] });
- }
- set({ parentId: item.id });
- getList({ parentId: item.id }); //请求对应文件夹列表
- }
- },
- [path, publicPath, mediaType, belongUser, isOk],
- );
- /**点击路径 */
- const pathClick = useCallback(
- (item) => {
- let newPath: any[] = [];
- if (belongUser == '1') {
- path?.forEach((paths, index) => {
- //用传入的index和path循环的index对比小于等于index代表该保留的路径
- if (index <= item.index) {
- newPath.push(paths);
- }
- });
- set({ path: newPath });
- } else {
- publicPath?.forEach((paths, index) => {
- //用传入的index和path循环的index对比小于等于index代表该保留的路径
- if (index <= item.index) {
- newPath.push(paths);
- }
- });
- set({ publicPath: newPath });
- }
- set({ parentId: item.parentId });
- getList({
- pageSize: 30,
- pageNum: 1,
- mediaType,
- belongUser: belongUser === '0' ? false : true,
- parentId: item.id,
- });
- },
- [path, mediaType, belongUser, publicPath],
- );
- /**取消文件 */
- const offFile = useCallback(
- (e: any, item: { id: any }) => {
- let { id } = item;
- set({ selectFile: selectFile?.filter((i) => i !== id) });
- },
- [selectFile],
- );
- /**判断是取消还是选中文件的操作在点击打钩时使用 */
- const changeClickFile = useCallback((e: any, item: { id: any; folder?: boolean, url: string }, isAll?: boolean, noFile?: boolean) => {
- let { id, url } = item;
- e?.stopPropagation(); //阻止冒泡传递到文件夹被点击事件
- let state = selectItem?.some((i) => i.url === url);
- if (state) {
- //存在就是删除
- set({
- selectFile: selectFile?.filter((i) => i !== id),
- selectItem: selectItem?.filter((i: { url: string }) => i.url !== url),
- });
- } else {
- //否则新增
- if (num === 1) {
- if (state) {
- //存在就是删除
- set({ selectFile: selectFile?.filter((i) => i !== id), selectItem: [] });
- } else {
- //否则新增
- set({ selectFile: [id], selectItem: [item] });
- }
- } else {
- if (selectFile && num && selectFile?.length >= num) {
- message.error(`只能选择${num}张`);
- return;
- }
- let newSelectItem = selectItem || [];
- newSelectItem.push(item);
- set({ selectItem: newSelectItem, selectFile: [...(selectFile as number[]), id] });
- }
- }
- // }
- },
- [selectFile, mediaType, num],
- );
- /**开启删除弹窗 */
- const delPupOn = useCallback((delPupId) => {
- set({ delPupId });
- }, []);
- /**关闭删除弹窗并去除选中 */
- const delPupOff = useCallback(() => {
- set({ delPupId: '' });
- offFile(null, { id: delPupId });
- }, [delPupId]);
- /**编辑 */
- const editFile = useCallback((e?: any) => {
- e?.stopPropagation();
- onFile(null, rightClickPup, true, true);
- let obj = { fileVisible: true, actionItem: { ...rightClickPup, fileType: mediaType }, fileName: rightClickPup.title, sort: rightClickPup.sort };
- // if (rightClickPup?.mediaType === "video") {
- // obj['videoTitle'] = rightClickPup?.videoTitle || rightClickPup?.title;
- // obj['videoDescription'] = rightClickPup?.videoDescription;
- // }
- set(obj);
- },
- [rightClickPup],
- );
- /**取消编辑后清空选中存放的数据并关闭弹窗*/
- const offEditFile = useCallback(() => {
- set({
- fileVisible: false,
- imgVisrible: false,
- imgsVisrible: false,
- sortVisible: false,
- actionItem: '',
- fileName: '',
- selectFile: selectFile?.filter((id) => id !== actionItem?.id),
- sort: 0,
- });
- }, [selectFile, actionItem]);
- /**全选反选文件*/
- const allFile = useCallback(() => {
- let allArr: any[] = [], allFile: any[] = [];
- list?.data?.records?.forEach((item: { id: any }) => {
- allArr.push(item.id);
- allFile.push(item)
- });
- set({ selectFile: allArr.filter((i) => selectFile?.every((id) => id !== i)), selectItem: allFile.filter((i) => selectItem?.every((item: any) => item.id !== i.id)) });
- }, [selectFile, list, mediaType, selectItem]);
- return {
- state,
- init,
- set,
- addFile,
- addFolder,
- getList,
- dels,
- onFile,
- changeClickFile,
- allFile,
- delPupOn,
- delPupOff,
- editFile,
- offEditFile,
- nameOk,
- fileClick,
- treeClick,
- pathClick,
- addFiles,
- configSort,
- list,
- add,
- get,
- edit,
- typeEnum,
- get_folder_tree,
- edit_media_folder,
- };
- }
- export default useBdMediaPup;
|