ColumnModify.tsx 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. import React, { useEffect, useRef, useState } from 'react'
  2. import { Prompt } from 'react-router-dom'
  3. import {
  4. DragDropContext,
  5. Droppable,
  6. Draggable,
  7. DroppableProvided,
  8. DroppableStateSnapshot,
  9. DraggableProvided,
  10. DraggableStateSnapshot,
  11. DropResult,
  12. ResponderProvided,
  13. DraggingStyle,
  14. NotDraggingStyle
  15. } from 'react-beautiful-dnd'
  16. import useRequest from '@ahooksjs/use-request/es'
  17. import { useHistory } from 'react-router-dom'
  18. import { Modal, Popover, Upload, UploadProps, message } from 'antd'
  19. import { Input } from 'antd'
  20. import { SearchOutlined } from '@ant-design/icons'
  21. import { ReactComponent as File } from 'assets/file.svg'
  22. import { ReactComponent as Image } from 'assets/image.svg'
  23. import { ReactComponent as Close } from 'assets/close.svg'
  24. import { ReactComponent as Close2 } from 'assets/close2.svg'
  25. import { FilesSvg } from './ColumnEditor'
  26. import Picture from 'Activity/components/Picture'
  27. import { ColumnType } from './components/ColumnContent'
  28. import { MaterialService } from 'Material/Material.service'
  29. import { ColumnService, IDocsList, ISaveColumnDetailParams, IUploadFileRes } from './Column.service'
  30. import { ColumnStatus } from './components/ColumnCenter'
  31. import styles from './css/ColumnEditor.module.scss'
  32. const FroalaWrapper = React.lazy(() => import('components/FroalaWrapper'))
  33. interface IColumnModifyProps {
  34. articleId: number // 文章ID(笔记或观点的ID)
  35. }
  36. let timer: NodeJS.Timeout
  37. /**修改并发布-笔记/观点 */
  38. const ColumnModify: React.FC<IColumnModifyProps> = props => {
  39. const history = useHistory()
  40. const froalaInstanceRef = useRef<any>(null)
  41. const [froalaValue, setFroalaValue] = useState('') // 正文
  42. const [selectType, setSelectType] = useState(1) // 类型1:笔记,2:观点
  43. const [searchCategrayValue, setSearchCategrayValue] = useState<string>('') // 搜索行业标签
  44. const [searchCompanyValue, setSearchCompanyValue] = useState<string>('') // 搜索公司标签
  45. const [industryTags, setIndustryTags] = useState<string[]>([]) // 选中的行业标签
  46. const [companyTags, setCompanyTags] = useState<string[]>([]) // 选中的公司标签
  47. const [bigImg, setBigImg] = useState<string>() // 展开的图片
  48. const [title, setTitle] = useState<string>('') // 标题
  49. const [fileList, setFileList] = useState<IDocsList[]>([]) // 上传文件列表
  50. const [fileImageList, setFileImageList] = useState<IUploadFileRes[]>([]) // 上传图片列表
  51. const [clickType, setClickType] = useState<number>() // 记录点击操作
  52. const [hasModify, setHasModify] = useState(false) // 是否有变动
  53. useEffect(() => {
  54. const listener = (e: any) => {
  55. e.preventDefault()
  56. e.returnValue = '内容还未保存,确定离开吗?'
  57. }
  58. if (hasModify) {
  59. window.addEventListener('beforeunload', listener)
  60. }
  61. return () => {
  62. clearTimeout(timer)
  63. window.removeEventListener('beforeunload', listener)
  64. }
  65. }, [hasModify])
  66. useEffect(() => {
  67. props.articleId && getColumnDetail(props.articleId)
  68. getSearchIndustry('')
  69. // eslint-disable-next-line react-hooks/exhaustive-deps
  70. }, [props.articleId])
  71. // 详情
  72. const { data: columnDetail, run: getColumnDetail } = useRequest(ColumnService.getColumnDetail, {
  73. manual: true,
  74. formatResult: response => response.data.Data,
  75. onSuccess: res => {
  76. setSelectType(res.Type)
  77. setTitle(res.Title)
  78. setFroalaValue(res.Content)
  79. setFileList(res.Docs)
  80. setIndustryTags(res.IndustryTags)
  81. setCompanyTags(res.CompanyTags)
  82. const imgList = res?.ImgUrlList?.map((item: string, index: number) => ({ Id: index, ResourceUrl: item }))
  83. setFileImageList(imgList || [])
  84. }
  85. })
  86. // 保存前的校验
  87. const { loading: checkLoading, run: applyCheckColumnDetail } = useRequest(ColumnService.postCheckColumnDetail, {
  88. manual: true,
  89. onSuccess: res => {
  90. if (res.data.Success) {
  91. const previewDetail = formatPreviewDetail(clickType)
  92. applySaveColumnDetail(previewDetail)
  93. } else {
  94. message.error(res.data.Msg || res.data.ErrMsg)
  95. }
  96. }
  97. })
  98. // 保存
  99. const { loading: saveLoading, run: applySaveColumnDetail } = useRequest(ColumnService.postSaveColumnDetail, {
  100. manual: true,
  101. onSuccess: res => {
  102. res.data.Success ? message.success(res.data.Msg) : message.error(res.data.Msg || res.data.ErrMsg)
  103. res.data.Success && setHasModify(false)
  104. res.data.Success && history.push(`/column`)
  105. }
  106. })
  107. const { data: industryList, run: getSearchIndustry } = useRequest(ColumnService.getSearchIndustry, {
  108. manual: true,
  109. formatResult: response => response.data.Data
  110. })
  111. const { data: companyList, run: getSearchCompanyTags } = useRequest(ColumnService.getSearchCompanyTags, {
  112. manual: true,
  113. formatResult: response => response.data.Data
  114. })
  115. const handleFormatFileList = (item: IUploadFileRes) => {
  116. return {
  117. DocName: item.ResourceName,
  118. DocSuffix: computeFileSvgShow(item?.ResourceName || '', 'suffix'),
  119. DocUrl: item.ResourceUrl
  120. // DocIcon?: string
  121. } as IDocsList
  122. }
  123. const computeFileSvgShow = (name: string, type: 'suffix' | 'svg') => {
  124. if (!name) return
  125. const suffix = name?.split('.')?.pop()
  126. if (type === 'suffix') return suffix
  127. return FilesSvg?.find(item => item.suffix === suffix)?.svg
  128. }
  129. // 上传文件
  130. const uploadFileprops: UploadProps = {
  131. name: 'file',
  132. accept: '.doc,.docx,.xls,.xlsx,.ppt,.pptx,.pdf',
  133. headers: {
  134. authorization: 'authorization-text'
  135. },
  136. multiple: true,
  137. itemRender: () => {
  138. // 不渲染
  139. },
  140. beforeUpload: file => {
  141. const allowedExtensions = ['.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx', '.pdf']
  142. const fileExtension = file.name.substring(file.name.lastIndexOf('.')).toLowerCase()
  143. if (!allowedExtensions.includes(fileExtension)) {
  144. message.error('只允许上传.doc, .docx, .xls, .xlsx, .ppt, .pptx 和 .pdf 文件')
  145. return Upload.LIST_IGNORE
  146. }
  147. },
  148. customRequest: async options => {
  149. try {
  150. const response = await ColumnService.postUploadFile(options.file)
  151. if (!response.data.Success) return message.error(response.data.Msg || response.data.ErrMsg)
  152. const fileItem = handleFormatFileList(response.data?.Data)
  153. setFileList(prevList => [...(prevList || []), fileItem])
  154. setHasModify(true)
  155. } catch (error) {
  156. console.log(error)
  157. }
  158. }
  159. }
  160. // 上传图片
  161. const uploadImageprops: UploadProps = {
  162. name: 'file',
  163. accept: 'image/*',
  164. headers: {
  165. authorization: 'authorization-text'
  166. },
  167. multiple: true,
  168. maxCount: 6,
  169. itemRender: () => {
  170. // 不渲染
  171. },
  172. beforeUpload: file => {
  173. const isPNG = file.type.toLowerCase().includes('image')
  174. if (!isPNG) {
  175. message.error(`请上传图片`)
  176. }
  177. return isPNG || Upload.LIST_IGNORE
  178. },
  179. customRequest: async options => {
  180. try {
  181. if (fileImageList.length >= 6) return message.error('最多上传6张图片')
  182. const response = await MaterialService.postUploadImage(options.file)
  183. if (!response.data.Success) return message.error(response.data.Msg || response.data.ErrMsg)
  184. setFileImageList(prevList => {
  185. if (prevList?.length >= 6) {
  186. message.error('最多上传6张图片')
  187. return prevList
  188. }
  189. return [...(prevList || []), response.data.Data]
  190. })
  191. setHasModify(true)
  192. } catch (error) {
  193. console.log(error)
  194. }
  195. }
  196. }
  197. // 删除文件
  198. const handleDeleteFile = (file: IDocsList, e: React.MouseEvent) => {
  199. e.stopPropagation()
  200. setFileList(prevList => prevList.filter(item => item.DocName !== file.DocName))
  201. setHasModify(true)
  202. }
  203. // 删除图片
  204. const handleDeleteImg = (img: IUploadFileRes, e: React.MouseEvent) => {
  205. e.stopPropagation()
  206. setFileImageList(prevList => prevList.filter(item => item.Id !== img.Id))
  207. setHasModify(true)
  208. }
  209. const handleSelectType = (type: number) => {
  210. setSelectType(type)
  211. setHasModify(true)
  212. }
  213. // 关闭图片查看
  214. const handleToCloseBigImg = () => {
  215. setBigImg(undefined)
  216. }
  217. // 图片拖拽 start
  218. const reorder = (list: IUploadFileRes[], startIndex: number, endIndex: number) => {
  219. const result = Array.from(list)
  220. const [removed] = result.splice(startIndex, 1)
  221. result.splice(endIndex, 0, removed)
  222. return result
  223. }
  224. const getItemStyle = (isDragging: boolean, draggableStyle: DraggingStyle | NotDraggingStyle | undefined) =>
  225. ({
  226. userSelect: 'none',
  227. margin: `0 20px 20px 0`,
  228. background: isDragging ? '#ffffff' : '#ffffff',
  229. ...draggableStyle
  230. } as React.CSSProperties)
  231. const getListStyle = (isDraggingOver: boolean) => ({
  232. background: isDraggingOver ? '#ffffff' : '#ffffff',
  233. display: 'flex',
  234. overflow: 'auto'
  235. })
  236. const onDragEnd = (result: DropResult, provided: ResponderProvided) => {
  237. if (!result.destination) {
  238. return
  239. }
  240. const reorderedList = reorder(fileImageList, result.source.index, result.destination.index)
  241. setFileImageList(reorderedList)
  242. setHasModify(true)
  243. }
  244. // 图片拖拽 end
  245. // 修改并发布
  246. const handleToClick = (type: string) => {
  247. if (!columnDetail?.IsApprovalAdmin) return message.error('您没有权限操作')
  248. if (columnDetail?.Status !== ColumnStatus.Auditing) return message.error('该文章未提交审批或已审批')
  249. if (checkLoading || saveLoading) return
  250. const typeFn: {
  251. [key: string]: () => void
  252. } = {
  253. modify: () => {
  254. Modal.confirm({
  255. title: '提示',
  256. content: '确定修改并通过此内容的审核吗?',
  257. okText: '确定',
  258. cancelText: '取消',
  259. centered: true,
  260. closable: true,
  261. onOk: () => {
  262. handleApplyCheckColumnDetail(2)
  263. }
  264. })
  265. }
  266. }
  267. typeFn[type]()
  268. }
  269. // 保存/发布前先校验
  270. const handleApplyCheckColumnDetail = (doType: number) => {
  271. if (!title) return message.error('请输入标题')
  272. if (doType === 2 && !froalaValue) return message.error('请输入正文')
  273. if (doType === 2 && industryTags?.length === 0 && companyTags?.length === 0)
  274. return message.error('请选至少选择一个标签')
  275. setClickType(doType)
  276. const imgList = getImgUrlList(froalaValue)
  277. const uploadImgList = fileImageList?.map(item => item.ResourceUrl)
  278. applyCheckColumnDetail({ Content: froalaValue, ImgUrl: imgList.concat(uploadImgList) })
  279. }
  280. // 获取正文中添加的img地址
  281. const getImgUrlList = (str: string) => {
  282. // 匹配 <img> 标签的 src 属性
  283. const imgRegex = /<img[^>]+src="([^">]+)"/g
  284. // 使用正则表达式的 exec 方法来提取匹配的内容
  285. let match
  286. const imgSrcList = []
  287. while ((match = imgRegex.exec(str)) !== null) {
  288. const src = match[1] // 提取的 src 属性值
  289. imgSrcList.push(src)
  290. }
  291. return imgSrcList
  292. }
  293. // 标题
  294. const handleInputTitle = (e: React.ChangeEvent<HTMLInputElement>) => {
  295. setTitle(e.target.value)
  296. setHasModify(true)
  297. }
  298. // 正文编辑
  299. const handleChangeText = (value: string) => {
  300. setFroalaValue(value)
  301. setHasModify(true)
  302. }
  303. // 组合预览详情
  304. const formatPreviewDetail = (doType?: number) => {
  305. // 图片
  306. const imgList = fileImageList?.map(item => item.ResourceUrl)
  307. return {
  308. Id: props.articleId || 0,
  309. Content: froalaValue,
  310. IndustryTags: industryTags, // 行业标签
  311. CompanyTags: companyTags, // 公司标签
  312. DoType: doType || 0, // 1保存2发布
  313. ImgUrl: imgList,
  314. Docs: fileList,
  315. Title: title,
  316. Type: selectType, //类型1:笔记,2:观点
  317. IsApprovalPersonnel: true
  318. } as ISaveColumnDetailParams
  319. }
  320. // 搜索行业标签
  321. const handleChangeSearchCategrayValue = (e: React.ChangeEvent<HTMLInputElement>) => {
  322. setSearchCategrayValue(e.target.value.replace(/\s/g, ''))
  323. clearTimeout(timer)
  324. timer = setTimeout(() => {
  325. getSearchIndustry(e.target.value)
  326. }, 500)
  327. }
  328. // 搜索公司标签
  329. const handleChangeSearchCompanyValue = (e: React.ChangeEvent<HTMLInputElement>) => {
  330. setSearchCompanyValue(e.target.value.replace(/\s/g, ''))
  331. clearTimeout(timer)
  332. timer = setTimeout(() => {
  333. getSearchCompanyTags(e.target.value)
  334. }, 500)
  335. }
  336. // 删除行业标签
  337. const handleDeleteIndustry = (tag: string, e: React.MouseEvent) => {
  338. // 阻止冒泡
  339. e.stopPropagation()
  340. setIndustryTags(prevList => prevList.filter(item => item !== tag))
  341. setHasModify(true)
  342. }
  343. // 删除公司标签
  344. const handleDeleteCompany = (tag: string, e: React.MouseEvent) => {
  345. e.stopPropagation()
  346. setCompanyTags(prevList => prevList.filter(item => item !== tag))
  347. setHasModify(true)
  348. }
  349. // 添加公司标签
  350. const handleAddCompanyTag = () => {
  351. if (!searchCompanyValue) return message.error('请输入标签')
  352. if (companyTags?.includes(searchCompanyValue)) return message.error('已存在该标签')
  353. setCompanyTags(prevList => [...prevList, searchCompanyValue])
  354. setSearchCompanyValue('')
  355. setHasModify(true)
  356. }
  357. // 选中的标签
  358. const handleAddTags = (actItem: string, type: 'industry' | 'company') => {
  359. if (type === 'industry') {
  360. // 如果存在则删除
  361. if (industryTags?.includes(actItem)) {
  362. setIndustryTags(prevList => prevList.filter(item => item !== actItem))
  363. return
  364. }
  365. setIndustryTags(prevList => [...prevList, actItem])
  366. } else {
  367. // 如果存在则删除
  368. if (companyTags?.includes(actItem)) {
  369. setCompanyTags(prevList => prevList.filter(item => item !== actItem))
  370. return
  371. }
  372. setCompanyTags(prevList => [...prevList, actItem])
  373. }
  374. setHasModify(true)
  375. }
  376. return (
  377. <div className={styles['columnedit-page']} style={{ overflow: 'auto', height: '100%' }}>
  378. <Prompt message="您有未保存的数据,确定离开本页面吗?" when={hasModify} />
  379. <Picture visible={!!bigImg} imgSrc={bigImg} onClose={handleToCloseBigImg} />
  380. <div className="columnedit-top">
  381. <strong>发布内容</strong>
  382. <div className="columnedit-select">
  383. <span
  384. className={`columnedit-select-label ${
  385. selectType === ColumnType.Note ? 'columnedit-active' : 'columnedit-notselect'
  386. }`}
  387. onClick={handleSelectType.bind(this, ColumnType.Note)}
  388. >
  389. 笔记
  390. </span>
  391. <span
  392. className={`columnedit-select-label ${
  393. selectType === ColumnType.Viewpoint ? 'columnedit-active' : 'columnedit-notselect'
  394. }`}
  395. onClick={handleSelectType.bind(this, ColumnType.Viewpoint)}
  396. >
  397. 观点
  398. </span>
  399. </div>
  400. </div>
  401. <div className="columnedit-title-wrapper">
  402. <input
  403. type="text"
  404. placeholder="请输入标题"
  405. className="columnedit-title-input"
  406. value={title}
  407. onChange={handleInputTitle}
  408. />
  409. </div>
  410. <div className="columnedit-edit-wrapper">
  411. <FroalaWrapper
  412. handleUpstream={editorInstance => {
  413. froalaInstanceRef.current = editorInstance
  414. }}
  415. value={froalaValue}
  416. onChange={handleChangeText}
  417. configType="column"
  418. />
  419. </div>
  420. <div className="columnedit-edit-operate-wrapper">
  421. <div className="operate-file-wrapper">
  422. {fileList?.map((item, index) => (
  423. <div className="operate-file-item" key={index}>
  424. <div className="g-flex g-flex-v-center">
  425. {computeFileSvgShow(item.DocName, 'svg')}
  426. <span className="operate-file-text">{item.DocName}</span>
  427. </div>
  428. <Close className="delete-file" onClick={handleDeleteFile.bind(this, item)} />
  429. </div>
  430. ))}
  431. </div>
  432. <div className="operate-file-wrapper">
  433. <DragDropContext onDragEnd={onDragEnd}>
  434. <Droppable droppableId="droppable" direction="horizontal">
  435. {(provided: DroppableProvided, snapshot: DroppableStateSnapshot) => (
  436. <div ref={provided.innerRef} style={getListStyle(snapshot.isDraggingOver)} {...provided.droppableProps}>
  437. {fileImageList?.map((item, index) => (
  438. <Draggable key={item.Id} draggableId={item.Id.toString()} index={index}>
  439. {(provided2: DraggableProvided, snapshot2: DraggableStateSnapshot) => (
  440. <div
  441. ref={provided2.innerRef}
  442. {...provided2.draggableProps}
  443. {...provided2.dragHandleProps}
  444. style={getItemStyle(snapshot2.isDragging, provided2.draggableProps.style)}
  445. >
  446. <div className="operate-image-item">
  447. <img src={item?.ResourceUrl} alt="图片" className="operate-image" />
  448. <Close2 className="delete2-select" onClick={handleDeleteImg.bind(this, item)} />
  449. </div>
  450. </div>
  451. )}
  452. </Draggable>
  453. ))}
  454. {provided.placeholder}
  455. </div>
  456. )}
  457. </Droppable>
  458. </DragDropContext>
  459. </div>
  460. <div className="operate-btn-wrapper">
  461. <div className="operate-left-btn">
  462. <Upload {...uploadFileprops}>
  463. <div className="operate-btn-item operate-upload-btn">
  464. <File className="upload-file-icon" />
  465. <span className="upload-file-text">上传文件</span>
  466. </div>
  467. </Upload>
  468. <Upload {...uploadImageprops}>
  469. <div className="operate-btn-item operate-upload-btn">
  470. <Image className="upload-file-icon" />
  471. <span className="upload-file-text">上传图片</span>
  472. </div>
  473. </Upload>
  474. <Popover
  475. content={
  476. <div className={styles['operate-select-label']}>
  477. <div className="operate-select-search">
  478. <SearchOutlined className="com-fz16" />
  479. <Input
  480. className="operate-search-input"
  481. placeholder="搜索行业分类"
  482. size="large"
  483. variant="borderless"
  484. value={searchCategrayValue}
  485. onChange={handleChangeSearchCategrayValue}
  486. />
  487. </div>
  488. <div className="selected-line">
  489. <div className="select-title">
  490. <span>已选标签</span>
  491. <span className="select-tips-gray">
  492. {industryTags.length === 0 ? '至少添加一个标签' : `已选${industryTags.length}个标签`}
  493. </span>
  494. </div>
  495. <div className={`${styles['select-item-wrapper']} selected-wrapper`}>
  496. {industryTags?.map(item => (
  497. <div className="select-item active-select-item" key={item}>
  498. <span>{item}</span>
  499. <Close className="delete-select" onClick={handleDeleteIndustry.bind(this, item)} />
  500. </div>
  501. ))}
  502. </div>
  503. </div>
  504. <div className="will-select-line">
  505. <div className="select-title">标签</div>
  506. <div className={`${styles['select-item-wrapper']} will-select-wrapper`}>
  507. {industryList?.map(item => (
  508. <div
  509. className={`select-item ${industryTags.includes(item) ? 'active-select-item' : ''}`}
  510. key={item}
  511. onClick={handleAddTags.bind(this, item, 'industry')}
  512. >
  513. <span>{item}</span>
  514. </div>
  515. ))}
  516. </div>
  517. </div>
  518. </div>
  519. }
  520. trigger="click"
  521. >
  522. <div className="operate-btn-item operate-add-label">
  523. {industryTags?.length ? (
  524. <div className={`${styles['select-item-wrapper']} operate-add-select`}>
  525. {industryTags.map(item => (
  526. <div className="select-item " key={item}>
  527. <span>{item}</span>
  528. </div>
  529. ))}
  530. </div>
  531. ) : (
  532. <span className="add-categray-label-text">添加行业标签</span>
  533. )}
  534. </div>
  535. </Popover>
  536. <Popover
  537. content={
  538. <div className={styles['operate-select-label']}>
  539. <div className="operate-select-search">
  540. <SearchOutlined className="com-fz16" />
  541. <Input
  542. className="operate-search-input"
  543. placeholder="搜索公司标签"
  544. size="large"
  545. variant="borderless"
  546. value={searchCompanyValue}
  547. onChange={handleChangeSearchCompanyValue}
  548. />
  549. <div className="create-company-btn" onClick={handleAddCompanyTag}>
  550. <span>+</span>
  551. <span className="m-l-xs">创建</span>
  552. </div>
  553. </div>
  554. <div className="selected-line">
  555. <div className="select-title">
  556. <span>已选标签</span>
  557. <span className="select-tips-gray">
  558. {companyTags.length === 0 ? '至少添加一个标签' : `已选${companyTags.length}个标签`}
  559. </span>
  560. </div>
  561. <div className={`${styles['select-item-wrapper']} selected-wrapper`}>
  562. {companyTags?.map(item => (
  563. <div className="select-item active-select-item" key={item}>
  564. <span>{item}</span>
  565. <Close className="delete-select" onClick={handleDeleteCompany.bind(this, item)} />
  566. </div>
  567. ))}
  568. </div>
  569. </div>
  570. <div className="will-select-line">
  571. <div className="select-title">标签</div>
  572. <div className={`${styles['select-item-wrapper']} will-select-wrapper`}>
  573. {companyList?.map(item => (
  574. <div
  575. className={`select-item ${companyTags.includes(item) ? 'active-select-item' : ''}`}
  576. key={item}
  577. onClick={handleAddTags.bind(this, item, 'company')}
  578. >
  579. <span>{item}</span>
  580. </div>
  581. ))}
  582. </div>
  583. </div>
  584. </div>
  585. }
  586. trigger="click"
  587. >
  588. <div className="operate-btn-item operate-add-label">
  589. {companyTags?.length ? (
  590. <div className={`${styles['select-item-wrapper']} operate-add-select`}>
  591. {companyTags?.map(item => (
  592. <div className="select-item " key={item}>
  593. <span>{item}</span>
  594. </div>
  595. ))}
  596. </div>
  597. ) : (
  598. <span className="add-company-label-text">添加公司标签</span>
  599. )}
  600. </div>
  601. </Popover>
  602. </div>
  603. <div className="operate-right-btn">
  604. <div className="operate-nomal-btn publish-btn" onClick={handleToClick.bind(this, 'modify')}>
  605. 修改并发布
  606. </div>
  607. </div>
  608. </div>
  609. </div>
  610. </div>
  611. )
  612. }
  613. export default ColumnModify