modalBox.tsx 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. import { Button, Card, Col, Empty, Image, Input, message, Modal, Pagination, Row, Select, Space, Tabs, Tag } from "antd"
  2. import React, { useMemo, useRef } from "react"
  3. import { useCallback, useEffect, useState } from "react"
  4. import { request, useModel } from "umi"
  5. import UploadModal from '@/pages/operatePage/material/cloud/components/Modal'
  6. const { TabPane } = Tabs;
  7. import style from './index.less'
  8. /**编辑器内容选择图片弹窗*/
  9. let config1 = {
  10. 1: '图片',
  11. 2: '音频',
  12. 3: '视频',
  13. 4: '文字',
  14. 5: '图文'
  15. }
  16. type Props = {
  17. mediaType: number,
  18. visible: boolean,
  19. onOk: (url: string, type?: number) => void,
  20. onCancel: () => void,
  21. title: string,
  22. actionKey?: string,
  23. isShowWx?: boolean,
  24. isAllData?: boolean
  25. }
  26. const ModalPage = (props: Props) => {
  27. const [action, setAction] = useState<string>('')
  28. const [actionData, setActionData] = useState<any>(null)
  29. const { mediaType, visible, onOk, onCancel, title, actionKey, isShowWx = true, isAllData = false } = props
  30. const [qqLink, setQqLink] = useState<string>('')
  31. const [key, setKey] = useState<string>('1')//菜单值
  32. const [page, setPage] = useState<number>(1)//页码
  33. let refM: { current: { onOpen: () => void, onCancel: () => void } } | any = useRef()//获取Modal实例方法
  34. const { access } = useModel('@@initialState', model => ({ access: model.initialState?.currentUser?.access }))
  35. const { getData, getWeData, addData, tagData, classGet, fileUrl } = useModel('useOperating.useMaterialContent', model => ({
  36. getData: model.getData,
  37. getWeData: model.getWeData,
  38. addData: model.addData,
  39. tagData: model.tagData,
  40. classGet: model.classGet,
  41. fileUrl: model.fileUrl,
  42. }))
  43. let { state } = useModel('useOperating.useMaterialModal')
  44. const { actionWX } = useModel('useOperating.useWxGroupList', model => ({ actionWX: model.state.actionWX }))
  45. const [className, setClassName] = useState<number>()
  46. const [tagName, setTagName] = useState<number[]>([])
  47. //搜索
  48. let handleSelect = useCallback((name: number | number[], isTag: boolean) => {
  49. if (isTag) {
  50. setTagName(name as number[])
  51. getData.run({ type: key === '3' ? 1 : 0, mediaType, groupId: className || '', tagIds: name, pageNum: 1, pageSize: 10 })
  52. setPage(1)
  53. } else {
  54. setClassName(name as number)
  55. getData.run({ type: key === '3' ? 1 : 0, mediaType, groupId: name || '', tagIds: tagName || '', pageNum: 1, pageSize: 10 })
  56. setPage(1)
  57. }
  58. }, [tagName, className, key, mediaType,])
  59. //
  60. let tagArr = useMemo(() => {
  61. if (tagData?.data) {
  62. let arr = tagData?.data?.map((item: { id: string, tagName: string }) => ({ value: item.id, text: item.tagName }))
  63. return arr
  64. }
  65. return []
  66. }, [tagData?.data])
  67. let classArr = useMemo(() => {
  68. if (classGet?.data) {
  69. let arrClass = classGet?.data?.map((item: { id: string, groupName: string }) => ({ value: item.id, text: item.groupName }))
  70. return arrClass
  71. }
  72. return []
  73. }, [classGet?.data])
  74. //
  75. useEffect(() => {
  76. getData.run({
  77. mediaType: mediaType,
  78. pageNum: 1,
  79. pageSize: 10,
  80. type: 0
  81. })
  82. }, [mediaType, actionWX])
  83. //qq视频
  84. const qqLinkChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
  85. let v = e.target.value
  86. let arr = v.split('/')
  87. let vid = arr[arr.length - 1].replace('.html', '')
  88. if (v.search(/http[s]?:\/\/v.qq.com[\S]*.html/ig) !== -1) {
  89. setQqLink(`https://v.qq.com/iframe/player.html?vid=${vid}&auto=0`)
  90. }
  91. }, [])
  92. //选中图片
  93. let handleClick = useCallback((url: any, data?: any) => {
  94. console.log(url)
  95. setAction(url)
  96. setActionData(data)
  97. }, [])
  98. //个人共用切换
  99. useEffect(() => {
  100. setPage(1)
  101. if (key === '1') {
  102. getData.run({
  103. mediaType: mediaType,
  104. pageNum: page,
  105. pageSize: 10,
  106. type: 0
  107. })
  108. tagData.run({ type: 0 })
  109. classGet.run({ type: 0 })
  110. }
  111. if (key === '3') {
  112. getData.run({
  113. mediaType: mediaType,
  114. pageNum: page,
  115. pageSize: 10,
  116. type: 1
  117. })
  118. tagData.run({ type: 1 })
  119. classGet.run({ type: 1 })
  120. }
  121. if (key === '4') {
  122. getWeData.run({
  123. appId: actionWX?.appid,
  124. size: 10,
  125. page: 0,
  126. type: mediaType
  127. })
  128. }
  129. }, [key, mediaType, actionWX])
  130. //翻页
  131. let pageSizeChange = useCallback((page: number, pageSize?: number) => {
  132. setPage(page)
  133. if (key === '1') {
  134. getData.run({
  135. mediaType: mediaType,
  136. pageNum: page,
  137. pageSize: 10,
  138. type: 0,
  139. tagIds: tagName || '',
  140. groupId: className || '',
  141. })
  142. } else {
  143. getData.run({
  144. mediaType: mediaType,
  145. pageNum: page,
  146. pageSize: 10,
  147. type: 1,
  148. tagIds: tagName || '',
  149. groupId: className || '',
  150. })
  151. }
  152. }, [mediaType, key, tagName, className])
  153. let wxpageSizeChange = useCallback((page: number, pageSize?: number) => {
  154. setPage(page)
  155. if (actionWX?.appid) {
  156. getWeData.run({
  157. appId: actionWX?.appid,
  158. size: pageSize,
  159. page: page,
  160. type: mediaType
  161. })
  162. }
  163. }, [mediaType, actionWX])
  164. //Ok
  165. let ok = () => {
  166. if (!actionKey) {
  167. if (isAllData) {
  168. if (actionData) {
  169. onOk(actionData, mediaType)
  170. }
  171. } else {
  172. if (action) {
  173. onOk(action, mediaType)
  174. }
  175. }
  176. }
  177. if (actionKey === '1') {
  178. if (qqLink) {
  179. onOk(qqLink)
  180. } else {
  181. message.error('地址不正确')
  182. }
  183. }
  184. }
  185. //新增编辑非图文素材弹窗确定发送
  186. let modalOk = useCallback((fnc: () => Promise<any>, data: any) => {
  187. fnc().then((res: any) => {
  188. if (res) {
  189. if (res?.file) {
  190. /**修改文件名以用户设置的文件title命名*/
  191. let newFile = new File([state?.file], res.title + '.' + state?.file?.name.split('.')[1], { type: state?.file?.type })
  192. let formData = new FormData();
  193. /**向阿里云请求上传地址*/
  194. fileUrl.run({ type: newFile.type }).then(res1 => {
  195. Object.keys(res1).forEach((key: string) => {
  196. if (key !== 'url') {
  197. formData.append(key, res1[key])
  198. }
  199. })
  200. formData.append('file', newFile)
  201. /**向阿里云返回的上传地址上传文件*/
  202. request(res1?.url, { method: 'post', body: formData }).then((res2: { code: number, data: { url: string } }) => {
  203. if (res2.code === 200) {
  204. message.success('上传成功')
  205. if (res) {
  206. /**取到返回的文件地址向后端发送具体数据*/
  207. if (res2?.data?.url) {
  208. addData.run({ title: res.title, url: res2?.data?.url, mediaTagIds: res.mediaTagId, mediaType, groupId: res.groupId, type: key === '3' ? 1 : 0 }).then(() => {
  209. refM?.current.onCancel()
  210. getData.refresh()
  211. })
  212. }
  213. }
  214. } else {
  215. message.error('上传失败!')
  216. }
  217. })
  218. })
  219. }
  220. }
  221. })
  222. }, [getData.data, state, key])
  223. let Tags = (props: { url: string, data?: { title?: string, name?: string } }) => {
  224. switch (mediaType) {
  225. case 1:
  226. return <Card bodyStyle={{ padding: 0, height: 150, display: 'flex', flexFlow: 'column' }} bordered={false} hoverable>
  227. <Image src={props.url} width={150} height={150} placeholder preview={false} onClick={() => handleClick(props.url, props?.data)} />
  228. </Card >
  229. case 3:
  230. return <div>
  231. <Card bodyStyle={{ padding: 10, height: 165, display: 'flex', flexFlow: 'column', border: '1px solid #efefef' }} bordered={false} hoverable onClick={() => handleClick(props.url, props?.data)}>
  232. <video src={props.url} height='130px' controls />
  233. <span>名称: {props?.data?.title || props?.data?.name}</span>
  234. </Card>
  235. </div>
  236. default:
  237. return <div>
  238. <Card bodyStyle={{ padding: 10, height: 80, display: 'flex', flexFlow: 'column', border: '1px solid #efefef' }} bordered={false} hoverable onClick={() => handleClick(props.url, props?.data)}>
  239. <audio src={props.url} controls />
  240. <span>名称: {props?.data?.title || props?.data?.name}</span>
  241. </Card>
  242. </div>
  243. }
  244. }
  245. return <Modal
  246. title={title}
  247. width={900}
  248. open={visible}
  249. onOk={ok}
  250. onCancel={onCancel}
  251. >
  252. <>
  253. {
  254. !actionKey && <>
  255. <Tabs
  256. type="card"
  257. onChange={(key: string) => { setKey(key) }}
  258. tabBarExtraContent={
  259. <Space>
  260. {
  261. key !== '4' && <Select
  262. style={{ width: 120 }}
  263. allowClear
  264. placeholder='标签搜索'
  265. onChange={(value: any) => handleSelect(value, true)}
  266. mode='multiple'
  267. filterOption={(input, option) =>
  268. (option?.children as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
  269. }
  270. >
  271. {
  272. tagArr?.map((item: { value: string, text: string }) => {
  273. return <Select.Option value={item.value} key={item.value}>{item.text}</Select.Option>
  274. })
  275. }
  276. </Select>
  277. }
  278. {
  279. key !== '4' && <Select
  280. showSearch
  281. style={{ width: 120 }}
  282. allowClear
  283. placeholder='类型搜索'
  284. onChange={(value: any) => handleSelect(value, false)}
  285. filterOption={(input, option) =>
  286. (option?.children as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
  287. }
  288. >
  289. {
  290. classArr?.map((item: { value: string, text: string }) => {
  291. return <Select.Option value={item.value} key={item.value}>{item.text}</Select.Option>
  292. })
  293. }
  294. </Select>
  295. }
  296. {
  297. key === '1' ?
  298. <Button type='primary' onClick={() => refM?.current?.onOpen('新建')}>新建{title}</Button> :
  299. key === '3' && access === 'admin' ? <Button type='primary' onClick={() => refM?.current?.onOpen('新建')}>新建{title}</Button> :
  300. key === '2' ? <Button type='primary' onClick={() => refM?.current?.onOpen('新建')}>新建{title}</Button> : ''
  301. }
  302. </Space>
  303. }
  304. >
  305. <TabPane tab="个人本地素材" key="1" style={{ padding: 10 }}>
  306. {
  307. getData?.data?.records?.length > 0 ? <Row justify='start' gutter={[15, 15]}>
  308. {
  309. getData?.data?.records?.map((item: any) => {
  310. return <Col key={item.id} className={`${style.img} ${action === item.url ? style.action : undefined}`}>
  311. <Tags url={item.url} data={item} />
  312. </Col>
  313. })
  314. }
  315. </Row> : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
  316. }
  317. <Pagination onChange={pageSizeChange} size={'small'} current={page} total={getData?.data?.total} style={{ float: 'right' }} showTotal={(total) => <Tag color="cyan">总共{total}数据</Tag>} />
  318. </TabPane>
  319. <TabPane tab="公共本地素材" key="3" style={{ padding: 10 }} >
  320. {
  321. getData?.data?.records?.length > 0 ? <Row justify='start' gutter={[15, 15]}>
  322. {
  323. getData?.data?.records?.map((item: any) => {
  324. return <Col key={item.id} className={`${style.img} ${action === item.url ? style.action : undefined}`}>
  325. <Tags url={item.url} data={item} />
  326. </Col>
  327. })
  328. }
  329. </Row> : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
  330. }
  331. <Pagination onChange={pageSizeChange} size={'small'} current={page} total={getData?.data?.total} style={{ float: 'right' }} showTotal={(total) => <Tag color="cyan">总共{total}数据</Tag>} />
  332. </TabPane>
  333. {
  334. isShowWx && false && <TabPane tab="微信素材" key="4" style={{ padding: 10 }}>
  335. {
  336. getWeData?.data?.records?.length > 0 ? <Row justify='start' gutter={[15, 15]}>
  337. {
  338. getWeData?.data?.records?.map((item: any) => {
  339. item = item?.content
  340. return <Col key={item?.mediaId} className={`${style.img} ${action === item?.url ? style.action : undefined}`}>
  341. <Tags url={item?.url} data={item} />
  342. </Col>
  343. })
  344. }
  345. </Row> : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
  346. }
  347. <Pagination onChange={wxpageSizeChange} size={'small'} current={page} total={getWeData?.data?.total} style={{ float: 'right' }} showTotal={(total) => <Tag color="cyan">总共{total}数据</Tag>} />
  348. </TabPane>
  349. }
  350. </Tabs>
  351. <UploadModal labelName={config1[mediaType as keyof typeof config1]} ref={refM} submit={modalOk} title={title} classs={classGet?.data} tags={tagData?.data} />
  352. </>
  353. }
  354. {
  355. actionKey === '1' &&
  356. <Tabs type="card">
  357. <TabPane tab="腾讯视频" key="2" style={{ padding: 10 }}>
  358. <Row>
  359. <Col className={style.qq_link}>
  360. <label>视频地址:</label>
  361. <Input placeholder='请输入腾讯视频地址' onChange={qqLinkChange} allowClear />
  362. </Col>
  363. <Col className={style.qq_iframe}>
  364. <label>预览:</label>
  365. <iframe
  366. data-vidtype="2"
  367. height="310"
  368. width="500"
  369. data-ratio="1.7666666666666666"
  370. data-w="848"
  371. src={qqLink}
  372. />
  373. </Col>
  374. </Row>
  375. </TabPane>
  376. </Tabs>
  377. }
  378. {
  379. actionKey === '2' && <Tabs type="card">
  380. <TabPane tab="音频" key="2" style={{ padding: 10 }}>
  381. <Row>
  382. <Col className={style.qq_link}>
  383. <label>视频地址:</label>
  384. <Input placeholder='请输入腾讯视频地址' />
  385. </Col>
  386. <Col className={style.qq_iframe}>
  387. <label>预览:</label>
  388. <iframe
  389. data-vidtype="2"
  390. height="310"
  391. width="500"
  392. data-ratio="1.7666666666666666"
  393. data-w="848"
  394. src="https://v.qq.com/iframe/player.html?vid=e3161ny316e&auto=0"
  395. />
  396. </Col>
  397. </Row>
  398. </TabPane>
  399. </Tabs>
  400. }
  401. </>
  402. </Modal>
  403. }
  404. export default ModalPage