| | |
| | | export default { |
| | | dev: { |
| | | SERVER_URL: 'https://jiashikang.cn/manage', |
| | | IMAGE_URL: 'https://jiashikang.cn/images/', // 图片地址 |
| | | // SERVER_URL: 'https://jiashikang.cn/manage', |
| | | SERVER_URL: 'http://192.168.110.111:9918', |
| | | IMAGE_URL: 'http://192.168.110.111:11223/images/', // 图片地址 |
| | | }, |
| | | test: { |
| | | SERVER_URL: 'http://221.182.45.100:8686', |
| | |
| | | "component": "./strategyManagement/index" |
| | | }, |
| | | { |
| | | "name": "新增公告", |
| | | "name": "新增攻略", |
| | | "path": "/strategyManagement/addAndEdit", |
| | | "component": "./strategyManagement/addAndEdit", |
| | | "hideInMenu": true |
| | |
| | | |
| | | // 获取实物商品订单列表 |
| | | export async function getPhysicalGoodsOrderList(params) { |
| | | return request('/t-physical-goods-order/pageList', { |
| | | return request('/t-ticket-order/pageList', { |
| | | method: 'POST', |
| | | data: params, |
| | | }); |
| | |
| | | |
| | | // 获取实物商品订单详情 |
| | | export async function getPhysicalGoodsOrderDetail(id) { |
| | | return request(`/t-physical-goods-order/detail/${id}`, { |
| | | return request(`/t-ticket-order/detail/${id}`, { |
| | | method: 'GET', |
| | | }); |
| | | } |
| | |
| | | const [form] = Form.useForm(); |
| | | const [searchParams] = useSearchParams(); |
| | | const [loading, setLoading] = useState(false); |
| | | const [coverImageUrl, setCoverImageUrl] = useState(''); |
| | | const [coverImageList, setCoverImageList] = useState([]); |
| | | const [detailImageList, setDetailImageList] = useState([]); |
| | | const [detailVideoList, setDetailVideoList] = useState([]); |
| | | const [detailTabActiveKey, setDetailTabActiveKey] = useState('image'); |
| | |
| | | form.setFieldsValue({ |
| | | title: data.title, |
| | | coverImage: data.coverImage, |
| | | sortOrder: data.sortOrder || 45, |
| | | sortOrder: data.sort || 45, |
| | | detailImages: data.detailImages, |
| | | detailVideos: data.detailVideos, |
| | | }); |
| | | |
| | | // 设置封面图 |
| | | if (data.coverImage) { |
| | | setCoverImageUrl(IMAGE_URL + data.coverImage); |
| | | // 判断是否是完整URL |
| | | const isFullUrl = data.coverImage.startsWith('http://') || data.coverImage.startsWith('https://'); |
| | | const imageUrl = isFullUrl |
| | | ? data.coverImage |
| | | : IMAGE_URL + data.coverImage.replace(/^\/+/, ''); // 去除开头的斜杠 |
| | | |
| | | setCoverImageList([ |
| | | { |
| | | uid: '-1', |
| | | name: 'coverImage.jpg', |
| | | status: 'done', |
| | | url: imageUrl, |
| | | response: data.coverImage, // 保存原始值(相对路径或完整URL) |
| | | }, |
| | | ]); |
| | | } else { |
| | | setCoverImageList([]); |
| | | } |
| | | |
| | | // 设置详情图 |
| | | if (data.detailImages) { |
| | | const imageArray = Array.isArray(data.detailImages) |
| | | ? data.detailImages |
| | | : data.detailImages.split(',').filter(Boolean); |
| | | const fileList = imageArray.map((url, index) => ({ |
| | | uid: `image-${index}`, |
| | | name: `image-${index}.jpg`, |
| | | status: 'done', |
| | | url: IMAGE_URL + url, |
| | | response: url, |
| | | })); |
| | | setDetailImageList(fileList); |
| | | } |
| | | // 根据type字段判断是图片还是视频,设置详情图/视频 |
| | | if (data.type === 1) { |
| | | // 类型为图片 |
| | | if (data.detailImages) { |
| | | const imageArray = Array.isArray(data.detailImages) |
| | | ? data.detailImages |
| | | : data.detailImages.split(',').filter(Boolean); |
| | | const fileList = imageArray.map((url, index) => { |
| | | const isFullUrl = url.startsWith('http://') || url.startsWith('https://'); |
| | | const imageUrl = isFullUrl |
| | | ? url |
| | | : IMAGE_URL + url.replace(/^\/+/, ''); |
| | | return { |
| | | uid: `image-${index}`, |
| | | name: `image-${index}.jpg`, |
| | | status: 'done', |
| | | url: imageUrl, |
| | | response: url, // 保存原始值 |
| | | }; |
| | | }); |
| | | setDetailImageList(fileList); |
| | | } |
| | | setDetailTabActiveKey('image'); |
| | | } else if (data.type === 2) { |
| | | // 类型为视频 |
| | | if (data.detailImages) { |
| | | const videoArray = Array.isArray(data.detailImages) |
| | | ? data.detailImages |
| | | : data.detailImages.split(',').filter(Boolean); |
| | | const fileList = videoArray.map((url, index) => { |
| | | const isFullUrl = url.startsWith('http://') || url.startsWith('https://'); |
| | | const videoUrl = isFullUrl |
| | | ? url |
| | | : IMAGE_URL + url.replace(/^\/+/, ''); |
| | | return { |
| | | uid: `video-${index}`, |
| | | name: `video-${index}.mp4`, |
| | | status: 'done', |
| | | url: videoUrl, |
| | | response: url, // 保存原始值 |
| | | }; |
| | | }); |
| | | setDetailVideoList(fileList); |
| | | } |
| | | setDetailTabActiveKey('video'); |
| | | } else { |
| | | // 兼容旧数据:如果type不存在,尝试从detailImages和detailVideos判断 |
| | | if (data.detailImages) { |
| | | const imageArray = Array.isArray(data.detailImages) |
| | | ? data.detailImages |
| | | : data.detailImages.split(',').filter(Boolean); |
| | | const fileList = imageArray.map((url, index) => { |
| | | const isFullUrl = url.startsWith('http://') || url.startsWith('https://'); |
| | | const imageUrl = isFullUrl |
| | | ? url |
| | | : IMAGE_URL + url.replace(/^\/+/, ''); |
| | | return { |
| | | uid: `image-${index}`, |
| | | name: `image-${index}.jpg`, |
| | | status: 'done', |
| | | url: imageUrl, |
| | | response: url, |
| | | }; |
| | | }); |
| | | setDetailImageList(fileList); |
| | | } |
| | | |
| | | // 设置详情视频 |
| | | if (data.detailVideos) { |
| | | const videoArray = Array.isArray(data.detailVideos) |
| | | ? data.detailVideos |
| | | : data.detailVideos.split(',').filter(Boolean); |
| | | const fileList = videoArray.map((url, index) => ({ |
| | | uid: `video-${index}`, |
| | | name: `video-${index}.mp4`, |
| | | status: 'done', |
| | | url: IMAGE_URL + url, |
| | | response: url, |
| | | })); |
| | | setDetailVideoList(fileList); |
| | | if (data.detailVideos) { |
| | | const videoArray = Array.isArray(data.detailVideos) |
| | | ? data.detailVideos |
| | | : data.detailVideos.split(',').filter(Boolean); |
| | | const fileList = videoArray.map((url, index) => { |
| | | const isFullUrl = url.startsWith('http://') || url.startsWith('https://'); |
| | | const videoUrl = isFullUrl |
| | | ? url |
| | | : IMAGE_URL + url.replace(/^\/+/, ''); |
| | | return { |
| | | uid: `video-${index}`, |
| | | name: `video-${index}.mp4`, |
| | | status: 'done', |
| | | url: videoUrl, |
| | | response: url, |
| | | }; |
| | | }); |
| | | setDetailVideoList(fileList); |
| | | } |
| | | } |
| | | |
| | | // 设置富文本内容 |
| | |
| | | let params = strategyContent; |
| | | params.content = html; |
| | | setStrategyContent(params); |
| | | form.setFieldsValue({ content: params }); |
| | | // form.setFieldsValue({ content: params }); |
| | | }; |
| | | |
| | | // 处理封面图上传成功 |
| | | const handleCoverImageSuccess = (response) => { |
| | | setCoverImageUrl(IMAGE_URL + response); |
| | | form.setFieldsValue({ coverImage: response }); |
| | | // 处理封面图上传变化 |
| | | const handleCoverImageChange = ({ fileList }) => { |
| | | setCoverImageList(fileList); |
| | | // 提取已上传成功的图片URL |
| | | const imagePath = fileList |
| | | .filter((file) => file.status === 'done') |
| | | .map((file) => { |
| | | if (file.response) { |
| | | return file.response; |
| | | } |
| | | if (file.url && file.url.startsWith(IMAGE_URL)) { |
| | | return file.url.replace(IMAGE_URL, ''); |
| | | } |
| | | return file.url; |
| | | }) |
| | | .filter(Boolean)[0]; |
| | | form.setFieldsValue({ coverImage: imagePath || '' }); |
| | | }; |
| | | |
| | | // 处理封面图删除 |
| | | const handleCoverImageRemove = (file) => { |
| | | setCoverImageList([]); |
| | | form.setFieldsValue({ coverImage: '' }); |
| | | return true; |
| | | }; |
| | | |
| | | // 自定义封面图上传请求 |
| | | const customCoverImageRequest = (options) => { |
| | | const { file, onSuccess, onError } = options; |
| | | uploadFile(file) |
| | | .then((ret) => { |
| | | if (ret && ret.data) { |
| | | onSuccess({ |
| | | uid: file.uid, |
| | | name: file.name, |
| | | status: 'done', |
| | | url: IMAGE_URL + ret.data, |
| | | response: ret.data, |
| | | }); |
| | | } else { |
| | | onError(); |
| | | } |
| | | }) |
| | | .catch(() => { |
| | | onError(); |
| | | }); |
| | | }; |
| | | |
| | | // 处理详情图片上传成功 |
| | |
| | | try { |
| | | const values = await form.validateFields(); |
| | | |
| | | console.log('wewqeqwe',detailImageList); |
| | | |
| | | |
| | | |
| | | // 验证封面图 |
| | | if (!coverImageUrl) { |
| | | const coverImage = values.coverImage; |
| | | if (!coverImage) { |
| | | message.error('请上传封面图'); |
| | | return; |
| | | } |
| | |
| | | return; |
| | | } |
| | | |
| | | // 根据当前选中的tab确定type |
| | | const type = detailTabActiveKey === 'image' ? 1 : 2; |
| | | |
| | | // 从 coverImageList 中取 response(相对路径字符串) |
| | | // 如果 response 是完整URL,提取相对路径 |
| | | const getRelativePath = (path) => { |
| | | if (!path) return ''; |
| | | if (path.startsWith('http://') || path.startsWith('https://')) { |
| | | // 如果是完整URL,尝试提取相对路径 |
| | | if (path.includes(IMAGE_URL)) { |
| | | return path.replace(IMAGE_URL, '').replace(/^\/+/, ''); |
| | | } |
| | | // 如果不在 IMAGE_URL 中,返回原值(可能是外部URL) |
| | | return path; |
| | | } |
| | | // 已经是相对路径,去除开头的斜杠 |
| | | return path.replace(/^\/+/, ''); |
| | | }; |
| | | |
| | | const coverImageResponse = coverImageList |
| | | .filter((file) => file.status === 'done') |
| | | .map((file) => getRelativePath(file.response)) |
| | | .filter(Boolean)[0] || ''; |
| | | |
| | | // detailImages 需要传字符串(逗号分隔) |
| | | const detailImagesStr = type === 1 |
| | | ? detailImageList |
| | | .filter((item) => item.status === 'done') |
| | | .map((item) => getRelativePath(item.response)) |
| | | .filter(Boolean) |
| | | .join(',') |
| | | : detailVideoList |
| | | .filter((item) => item.status === 'done') |
| | | .map((item) => getRelativePath(item.response)) |
| | | .filter(Boolean) |
| | | .join(','); |
| | | |
| | | // 准备提交数据 |
| | | const submitData = { |
| | | title: values.title, |
| | | coverImage: values.coverImage, |
| | | sortOrder: values.sortOrder || 45, |
| | | detailImages: values.detailImages || '', |
| | | detailVideos: values.detailVideos || '', |
| | | coverImage: coverImageResponse, // 只取 response(相对路径字符串) |
| | | sort: values.sortOrder || 45, |
| | | detailImages: detailImagesStr, // 传字符串(逗号分隔) |
| | | type: type, |
| | | content: strategyContent.content, |
| | | }; |
| | | |
| | |
| | | {/* 攻略标题 */} |
| | | <ProFormText |
| | | name="title" |
| | | label="*攻略标题" |
| | | label="攻略标题" |
| | | placeholder="请输入" |
| | | wrapperCol={{ span: 12 }} |
| | | rules={[{ required: true, message: '请输入攻略标题' }]} |
| | |
| | | <Upload |
| | | name="coverImage" |
| | | listType="picture-card" |
| | | showUploadList={false} |
| | | fileList={coverImageList} |
| | | beforeUpload={beforeUploadImage} |
| | | disabled={loading || isReadOnly} |
| | | customRequest={customRequest} |
| | | customRequest={customCoverImageRequest} |
| | | accept="image/*" |
| | | onSuccess={handleCoverImageSuccess} |
| | | onRemove={() => { |
| | | setCoverImageUrl(''); |
| | | form.setFieldsValue({ coverImage: '' }); |
| | | }} |
| | | onChange={handleCoverImageChange} |
| | | onRemove={handleCoverImageRemove} |
| | | > |
| | | {coverImageUrl ? ( |
| | | <img |
| | | src={coverImageUrl} |
| | | alt="封面图" |
| | | style={{ width: '100%', height: '100%', objectFit: 'cover' }} |
| | | /> |
| | | ) : ( |
| | | uploadButton |
| | | )} |
| | | {coverImageList.length >= 1 ? null : uploadButton} |
| | | </Upload> |
| | | </Form.Item> |
| | | |
| | |
| | | <ProFormDigit |
| | | name="sortOrder" |
| | | label="排序:" |
| | | placeholder="45" |
| | | placeholder="请输入" |
| | | min={0} |
| | | disabled={isReadOnly} |
| | | fieldProps={{ |
| | | style: { width: '120px' }, |
| | | }} |
| | | initialValue={45} |
| | | /> |
| | | <div style={{ fontSize: '12px', color: '#999', marginTop: '4px', marginLeft: '8px' }}> |
| | | 数值越大越靠前 |
| | |
| | | {/* 攻略内容 */} |
| | | <Form.Item |
| | | name="content" |
| | | label="*攻略内容" |
| | | label="攻略内容" |
| | | wrapperCol={{ span: 24 }} |
| | | rules={[{ required: true, message: '请输入攻略内容' }]} |
| | | // rules={[{ required: true, message: '请输入攻略内容' }]} |
| | | > |
| | | <BraftEditorCom |
| | | data={strategyContent.content || ''} |
| | |
| | | }, |
| | | }, |
| | | { |
| | | title: '发布时间', |
| | | dataIndex: 'publishTime', |
| | | valueType: 'date', |
| | | width: 150, |
| | | title: '创建时间', |
| | | dataIndex: 'createTime', |
| | | valueType: 'dateTime', |
| | | width: 180, |
| | | align: 'center', |
| | | hideInTable: false, |
| | | fieldProps: { |
| | |
| | | }, |
| | | }, |
| | | { |
| | | title: '浏览人数', |
| | | dataIndex: 'viewCount', |
| | | title: '创建人', |
| | | dataIndex: 'createBy', |
| | | hideInSearch: true, |
| | | width: 120, |
| | | align: 'center', |
| | | ellipsis: true, |
| | | }, |
| | | { |
| | | title: '浏览量', |
| | | dataIndex: 'lookNum', |
| | | hideInSearch: true, |
| | | width: 120, |
| | | align: 'center', |
| | | render: (text) => text || 0, |
| | | }, |
| | | { |
| | | title: '排序', |
| | | dataIndex: 'sort', |
| | | hideInSearch: true, |
| | | width: 100, |
| | | align: 'center', |
| | | render: (text) => text || 0, |
| | | }, |
| | | { |
| | | title: '类型', |
| | | dataIndex: 'type', |
| | | hideInSearch: true, |
| | | width: 100, |
| | | align: 'center', |
| | | render: (text) => { |
| | | if (text === 1) return '图片'; |
| | | if (text === 2) return '视频'; |
| | | return '-'; |
| | | }, |
| | | }, |
| | | { |
| | | title: '操作', |
| | |
| | | </Button>, |
| | | ]} |
| | | request={async (params, sort, filter) => { |
| | | const { current, pageSize, title, publishTime, ...rest } = params; |
| | | const { current, pageSize, title, createTime, ...rest } = params; |
| | | |
| | | const requestParams = { |
| | | ...rest, |
| | | pageNum: current, |
| | | pageSize, |
| | | title: title || undefined, |
| | | publishTime: publishTime || undefined, |
| | | createTime: createTime || undefined, |
| | | }; |
| | | |
| | | const res = await getStrategyList(requestParams); |
| | |
| | | |
| | | // 获取攻略列表(分页) |
| | | export async function getStrategyList(params) { |
| | | return request('/strategy/page', { |
| | | return request('/t-guide/pageList', { |
| | | method: 'POST', |
| | | data: params, |
| | | }); |
| | |
| | | |
| | | // 删除攻略 |
| | | export async function deleteStrategy(id) { |
| | | return request(`/strategy/${id}`, { |
| | | return request(`/t-guide/delete/${id}`, { |
| | | method: 'DELETE', |
| | | }); |
| | | } |
| | | |
| | | // 获取攻略详情 |
| | | export async function getStrategyDetail(id) { |
| | | return request(`/strategy/${id}`, { |
| | | return request(`/t-guide/detail/${id}`, { |
| | | method: 'GET', |
| | | }); |
| | | } |
| | | |
| | | // 新增攻略 |
| | | export async function addStrategy(params) { |
| | | return request('/strategy', { |
| | | return request('/t-guide/add', { |
| | | method: 'POST', |
| | | data: params, |
| | | }); |
| | |
| | | |
| | | // 编辑攻略 |
| | | export async function editStrategy(params) { |
| | | return request('/strategy', { |
| | | method: 'PUT', |
| | | return request('/t-guide/update', { |
| | | method: 'post', |
| | | data: params, |
| | | }); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | |