123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533 |
- 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,//img,voice,video弹窗
- 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, // 上传loading
- }
- export type Action = {
- type: 'set' | 'init',
- params?: any
- }
- const typeEnum = {
- 'IMG': '图片',
- 'VIDEO': '视频',
- 'PAGE': '落地页'
- }
- 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,
- fileName: '',
- videoTitle: '',
- videoDescription: '',
- 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,
- }
- /**本地素材管理器 */
- function useBdMediaPup() {
- const [state, dispatch]: [State, Dispatch<Action>] = useReducer(reducer, initData)
- const { fileName, sort, belongUser, mediaType, parentId, selectFile, delPupId, rightClickPup, actionItem, path, publicPath, size, videoTitle, videoDescription } = state
- const list = useAjax((params) => bdSysMediaList(params))
- const add = useAjax((params) => bdSysMediaAdd(params), { msgNmae: '新增' })
- const adds = useAjax((params) => bdSysMediaAddsApi(params), { msgNmae: '新增' })
- const del = useAjax((params) => delMedia(params), { msgNmae: '删除' })
- const edit = useAjax((params) => bdSysMediaEdit(params), { msgNmae: '编辑' })
- const configSort = useAjax((params) => configSortApi(params), { msgNmae: '排序' })
- const get_folder_tree = useAjax((params: any) => getFolderTree(params))
- const edit_media_folder = useAjax((params: any) => editMediaFolder(params))
- const get = useAjax((params) => getMedia(params))//获取本地素材详情
- const [isOk, setIsOk] = useState<boolean>(true)
- //请求上传地址
- const fileUrl = useAjax((params: { type: string, fileType: 'video' | 'image' }) => getFileUrl(params), {
- manual: true,
- })
- /**初始化数据 */
- const init = useCallback((params: any) => {
- console.log('init===>', params)
- dispatch({ type: 'init', params })
- }, [])
- /**设置state */
- const set = useCallback((params: State) => {
- // console.log('params===>',params)
- 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, fileSize / 1024 - 50)
- if (bole?.size > fileSize) {
- bole = await compressAccurately(file, fileSize / 1024 - 100)
- }
- if (bole?.size > fileSize) {
- bole = await compressAccurately(file, fileSize / 1024 - 150)
- }
- if (bole?.size > fileSize) {
- bole = await compressAccurately(file, fileSize / 1024 - 200)
- }
- 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\\\\]+$/))) {
- obj.title = obj.title.replace(RegExp(/^[^\\<\\>\\&'\\\"\\x08\\x09\\x0A\\x0D\\\\]+$/), '')
- }
- 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 ? data.title + '_' + (index + 1).toString() : data.title, 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: 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) => {
- let obj = { pageSize: 30, pageNum: 1, belongUser: belongUser === '0' ? false : true, mediaType, parentId, ...props }
- list.run(obj).then((res) => {
- setIsOk(true)
- })
- }, [mediaType, belongUser, parentId])
- /**选中文件 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)
- console.log(item, belongUser == '1')
- 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(item?.id === 0 ? { path: [path[0]] } : { path: [path[0], item] })
- }
- if (belongUser == '0' && publicPath) {
- set(item?.id === 0 ? { publicPath: [publicPath[0]] } : { 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 })
- console.log(item)
- getList({ pageSize: 30, pageNum: 1, mediaType, belongUser: belongUser === '0' ? false : true, parentId: item.id })
- console.log('文件夹被点击')
- }, [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 }, isAll?: boolean) => {
- let { id } = item
- e?.stopPropagation()//阻止冒泡传递到文件夹被点击事件
- let state = selectFile?.some((i) => i === id)
- if (isAll) {
- if (state) {//存在就是删除
- set({ selectFile: selectFile?.filter(i => i !== id) })
- } else {//否则新增
- set({ selectFile: [...selectFile as number[], id] })
- }
- } else {//单选情况存在于选择素材弹窗组件
- if (item?.folder && mediaType !== 'IMG') {//假如是文件不让选择
- message.error('不能选择文件夹')
- return
- }
- if (state) {//存在就是删除
- set({ selectFile: selectFile?.filter(i => i !== id) })
- set({ selectItem: null })
- } else {//否则新增
- set({ selectFile: [id] })
- set({ selectItem: item })
- }
- }
- }, [selectFile, mediaType])
- /**开启删除弹窗 */
- 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[] = []
- list?.data?.records?.forEach((item: { id: any }) => {
- allArr.push(item.id)
- })
- set({ selectFile: allArr.filter((i) => selectFile?.every(id => id !== i)) })
- }, [selectFile, list, mediaType])
- return {
- state,
- init,
- set,
- addFile,
- addFolder,
- getList,
- dels,
- onFile,
- changeClickFile,
- allFile,
- delPupOn,
- delPupOff,
- editFile,
- offEditFile,
- nameOk,
- fileClick,
- treeClick,
- pathClick,
- addFiles,
- configSort,
- fileUrl,
- list,
- add,
- get,
- edit,
- typeEnum,
- get_folder_tree,
- edit_media_folder
- }
- }
- export default useBdMediaPup
|