From 20e32587ecbab27e4436f2f64a15faa3c89e4f41 Mon Sep 17 00:00:00 2001 From: pyt <626651354@qq.com> Date: 星期二, 20 五月 2025 21:39:59 +0800 Subject: [PATCH] Merge branch 'master' of http://120.76.84.145:10101/gitblit/r/H5/threeSide --- management/src/pages/appeal-management/detail.jsx | 235 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 224 insertions(+), 11 deletions(-) diff --git a/management/src/pages/appeal-management/detail.jsx b/management/src/pages/appeal-management/detail.jsx index e8d4ae5..950943f 100644 --- a/management/src/pages/appeal-management/detail.jsx +++ b/management/src/pages/appeal-management/detail.jsx @@ -1,13 +1,14 @@ import { buildProTableDataSource, sendRequest, showDelConfirm } from '@/utils/antdUtils'; import { PageContainer, ProTable } from '@ant-design/pro-components'; -import { Button, Card, Select, Space, Descriptions, Divider, Steps, message } from 'antd'; +import { Button, Card, Select, Space, Descriptions, Divider, Steps, message, Modal, Form, Input, Upload, Popconfirm } from 'antd'; import { useRef, useState, useEffect } from 'react'; import { Access, useAccess } from 'umi' import { history, useLocation } from "@umijs/max" -import { getDetail } from './service'; +import { getDetail, editProgress, deleteProgress } from './service'; import moment from 'moment'; import './index.less'; -import {downLoad } from '@/utils/utils'; +import {downLoad, customRequest } from '@/utils/utils'; +import { PlusOutlined } from '@ant-design/icons'; const Account = () => { const actionRef = useRef(); @@ -16,6 +17,22 @@ const [detail, setDetail] = useState({}); const searchParams = new URLSearchParams(useLocation().search); const id = searchParams.get('id'); + const [editModalVisible, setEditModalVisible] = useState(false); + const [editProgressData, setEditProgressData] = useState(null); + const [editForm] = Form.useForm(); + const [loading, setLoading] = useState(false); + const [imgFileList, setImgFileList] = useState([]); + const [videoFileList, setVideoFileList] = useState([]); + const [previewVisible, setPreviewVisible] = useState(false); + const [previewImage, setPreviewImage] = useState(''); + const [previewType, setPreviewType] = useState('image'); // 'image' or 'video' + const uploadConfig = { + name: 'file', + action: 'https://huacheng.psciio.com/api/huacheng-communitybackstage/communitypartybuilding/uploadimage', + headers: { + Authorization: 'Bearer ' + localStorage.getItem('token'), + }, + }; useEffect(() => { getDetail({ id: id }).then((res) => { @@ -111,6 +128,117 @@ span: 4, }, ]; + + // 上传前校验 + const beforeUpload = (file) => { + return new Promise((resolve, reject) => { + if (file.name.includes(',')) { + message.warning('上传文件不能包含英文逗号(,)'); + return Upload.LIST_IGNORE; + } + setLoading(true); + resolve(file); + }); + }; + + // 图片上传change + const handleImgChange = ({ file, fileList: newFileList }) => { + if (file.status === 'error' || (file.status === 'done' && file.response && file.response.code !== 200)) { + setLoading(false); + setImgFileList([]); + message.error('上传失败'); + editForm.setFieldValue('imgUrl', []); + return; + } + if (file.status === 'done' && file.response && file.response.code === 200) { + setLoading(false); + message.success('上传成功'); + } + let urls = newFileList.map(item => { + if (item.status === 'done' && item.response && item.response.data) { + item.url = item.response.data; + } + return item.url || item.url; + }).filter(Boolean); + setImgFileList(newFileList); + editForm.setFieldValue('imgUrl', urls); + }; + + // 视频上传change + const handleVideoChange = ({ file, fileList: newFileList }) => { + if (file.status === 'error' || (file.status === 'done' && file.response && file.response.code !== 200)) { + setLoading(false); + setVideoFileList([]); + message.error('上传失败'); + editForm.setFieldValue('videoUrl', []); + return; + } + if (file.status === 'done' && file.response && file.response.code === 200) { + setLoading(false); + message.success('上传成功'); + } + let urls = newFileList.map(item => { + if (item.status === 'done' && item.response && item.response.data) { + item.url = item.response.data; + } + return item.url || item.url; + }).filter(Boolean); + setVideoFileList(newFileList); + editForm.setFieldValue('videoUrl', urls); + }; + + // 办理进度编辑提交 + const handleEditProgress = async () => { + try { + setLoading(true); + console.log('editProgressData', editProgressData); + + const values = await editForm.validateFields(); + await editProgress({ + complaintId: id, + describe: values.describe, + id: editProgressData.id, + imgUrl: (values.imgUrl || []).join(','), + video: (values.videoUrl || []).join(',') + }); + message.success('编辑成功'); + setEditModalVisible(false); + getDetail({ id }).then((res) => setDetail(res.data)); + } catch (e) { + // 校验或请求失败 + } finally { + setLoading(false); + } + }; + + // 办理进度删除 + const handleDeleteProgress = async (progressId) => { + try { + await deleteProgress({ id: progressId }); + message.success('删除成功'); + getDetail({ id }).then((res) => setDetail(res.data)); + } catch (e) { + message.error('删除失败'); + } + }; + + // 在弹窗打开时同步 fileList + useEffect(() => { + if (editModalVisible && editProgressData) { + setImgFileList((editProgressData.imgUrl ? editProgressData.imgUrl.split(',') : []).map((url, idx) => ({ uid: idx, url, status: 'done' }))); + setVideoFileList((editProgressData.video ? editProgressData.video.split(',') : []).map((url, idx) => ({ uid: idx, url, status: 'done' }))); + editForm.setFieldsValue({ + describe: editProgressData.describe, + imgUrl: editProgressData.imgUrl ? editProgressData.imgUrl.split(',') : [], + videoUrl: editProgressData.video ? editProgressData.video.split(',') : [], + }); + } + if (!editModalVisible) { + setImgFileList([]); + setVideoFileList([]); + } + }, [editModalVisible, editProgressData]); + return ( <div> <PageContainer className={'appeal-management-detail'} header={{ breadcrumb: {} }} title="述求详情" > @@ -121,22 +249,34 @@ <Descriptions title="办理进度" column={1}> {detail.complaintProgresses?.length > 0 ? detail.complaintProgresses.map((item, index) => ( <Descriptions.Item key={index}> - <Card style={{ width: '800px' }} title={item.createByName} extra={moment(item.createTime).format('YYYY-MM-DD HH:mm:ss')}> + <Card style={{ width: '800px', position: 'relative' }} title={item.createByName} extra={moment(item.createTime).format('YYYY-MM-DD HH:mm:ss')}> <Descriptions column={1} > - <Descriptions.Item> - {item.describe} - </Descriptions.Item> + <Descriptions.Item>{item.describe}</Descriptions.Item> <Descriptions.Item label={'上传图片'}> - {item.imgUrl && (item.imgUrl || '').split(',').map((item, index) => ( - <img width={80} style={{ marginRight: '10px' }} height={80} src={item} key={index} alt="example" /> + {item.imgUrl && (item.imgUrl || '').split(',').map((img, idx) => ( + <img width={80} style={{ marginRight: '10px' }} height={80} src={img} key={idx} alt="example" /> ))} </Descriptions.Item> <Descriptions.Item label={'上传视频'}> - {item.videoUrl && (item.videoUrl || '').split(',').map((item, index) => ( - <video width={280} style={{ marginRight: '10px' }} src={item} key={index} controls></video> + {item.video && item.video.split(',').map((video, idx) => ( + <video width={280} style={{ marginRight: '10px' }} src={video} key={idx} controls></video> ))} </Descriptions.Item> </Descriptions> + <div style={{ position: 'absolute', right: 24, bottom: 16 }}> + <Button size="small" type="primary" style={{ marginRight: 8 }} onClick={() => { + setEditProgressData(item); + setEditModalVisible(true); + editForm.setFieldsValue({ + describe: item.describe, + imgUrl: item.imgUrl ? item.imgUrl.split(',') : [], + videoUrl: item.video ? item.video.split(',') : [], + }); + }}>编辑</Button> + <Popconfirm title="确定要删除该办理进度吗?" onConfirm={() => handleDeleteProgress(item.id)} okText="确定" cancelText="取消"> + <Button size="small" danger>删除</Button> + </Popconfirm> + </div> </Card> </Descriptions.Item> )) : <Descriptions.Item span={4} >暂无办理进度</Descriptions.Item>} @@ -252,7 +392,80 @@ </div> </Card> + <Modal + title="编辑办理进度" + open={editModalVisible} + onCancel={() => setEditModalVisible(false)} + onOk={handleEditProgress} + confirmLoading={loading} + destroyOnClose + width={600} + > + <Form form={editForm} layout="vertical" initialValues={{ describe: '', imgUrl: [], videoUrl: [] }}> + <Form.Item name="describe" label="办理进度描述" rules={[{ required: true, message: '请输入办理进度描述' }]}> + <Input.TextArea rows={4} maxLength={500} showCount /> + </Form.Item> + <Form.Item name="imgUrl" label="图片:"> + <Upload + {...uploadConfig} + listType="picture-card" + maxCount={9} + beforeUpload={beforeUpload} + onChange={handleImgChange} + onRemove={() => { + setImgFileList([]); + editForm.setFieldValue('imgUrl', []); + }} + showUploadList={{ showPreviewIcon: true }} + accept="image/*" + fileList={imgFileList} + onPreview={file => { + setPreviewType('image'); + setPreviewImage(file.url || file.thumbUrl); + setPreviewVisible(true); + }} + > + {imgFileList.length < 9 && <PlusOutlined />} + </Upload> + </Form.Item> + <Form.Item name="videoUrl" label="视频:"> + <Upload + {...uploadConfig} + listType="picture-card" + maxCount={9} + beforeUpload={beforeUpload} + onChange={handleVideoChange} + onRemove={() => { + setVideoFileList([]); + editForm.setFieldValue('videoUrl', []); + }} + showUploadList={{ showPreviewIcon: true }} + accept="video/*" + fileList={videoFileList} + onPreview={file => { + setPreviewType('video'); + setPreviewImage(file.url || file.thumbUrl); + setPreviewVisible(true); + }} + > + {videoFileList.length < 9 && <PlusOutlined />} + </Upload> + </Form.Item> + </Form> + </Modal> + <Modal + open={previewVisible} + footer={null} + onCancel={() => setPreviewVisible(false)} + width={previewType === 'video' ? 800 : 600} + > + {previewType === 'image' ? ( + <img alt="预览" style={{ width: '100%' }} src={previewImage} /> + ) : ( + <video style={{ width: '100%' }} src={previewImage} controls autoPlay /> + )} + </Modal> </PageContainer> </div> ); -- Gitblit v1.7.1