zjk
2026-01-04 7ea6e580fca51a45a0b3769ac4368e8b2bd41688
Merge branch 'main' of http://120.76.84.145:10101/gitblit/r/H5/qingduTicketing
12个文件已修改
715 ■■■■■ 已修改文件
management/config/env.ts 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/config/routes.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/src/pages/announcementManagement/addAndEdit.jsx 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/src/pages/announcementManagement/index.jsx 111 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/src/pages/announcementManagement/service.js 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/src/pages/order/orderList/index.jsx 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/src/pages/order/orderList/service.js 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/src/pages/order/refundAudit/index.jsx 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/src/pages/order/refundAudit/service.js 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/src/pages/strategyManagement/addAndEdit.jsx 268 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/src/pages/strategyManagement/index.jsx 103 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/src/pages/strategyManagement/service.js 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/config/env.ts
@@ -1,7 +1,8 @@
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',
management/config/routes.ts
@@ -72,7 +72,7 @@
        "component": "./strategyManagement/index"
      },
      {
        "name": "新增公告",
        "name": "新增攻略",
        "path": "/strategyManagement/addAndEdit",
        "component": "./strategyManagement/addAndEdit",
        "hideInMenu": true
management/src/pages/announcementManagement/addAndEdit.jsx
@@ -66,29 +66,44 @@
          form.setFieldsValue({
            title: data.title,
            sortOrder: data.sortOrder || 45,
            homepageDisplay: data.homepageDisplay === 1,
            showOnHome: data.showOnHome === true || data.showOnHome === 'true' || data.showOnHome === 1,
            coverImage: data.coverImage,
            carouselImages: data.carouselImages,
            detailImages: data.detailImages,
          });
          // 设置封面图
          if (data.coverImage) {
            setCoverImageUrl(IMAGE_URL + data.coverImage);
            const isFullUrl = data.coverImage.startsWith('http://') || data.coverImage.startsWith('https://');
            const imageUrl = isFullUrl
              ? data.coverImage
              : IMAGE_URL + data.coverImage.replace(/^\/+/, '');
            setCoverImageUrl(imageUrl);
          }
          // 设置轮播图
          if (data.carouselImages) {
            const imageArray = Array.isArray(data.carouselImages)
              ? data.carouselImages
              : data.carouselImages.split(',').filter(Boolean);
            const fileList = imageArray.map((url, index) => ({
              uid: `-${index}`,
              name: `image-${index}.jpg`,
              status: 'done',
              url: IMAGE_URL + url,
            }));
          if (data.detailImages) {
            const imageArray = Array.isArray(data.detailImages)
              ? data.detailImages
              : typeof data.detailImages === 'string'
                ? 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: `-${index}`,
                name: `image-${index}.jpg`,
                status: 'done',
                url: imageUrl,
                response: url, // 保存原始值
              };
            });
            setCarouselImageList(fileList);
            form.setFieldValue('carouselImages', imageArray.join(','));
            // 将 detailImages 设置为逗号分隔的字符串
            const detailImagesStr = imageArray.join(',');
            form.setFieldValue('detailImages', detailImagesStr);
          }
          // 设置富文本内容
@@ -108,12 +123,14 @@
    let params = announcementContent;
    params.content = html;
    setAnnouncementContent(params);
    form.setFieldsValue({ content: params });
    // form.setFieldsValue({ content: params });
  };
  // 处理封面图上传成功
  const handleCoverImageSuccess = (response) => {
    setCoverImageUrl(IMAGE_URL + response);
    const isFullUrl = response && (response.startsWith('http://') || response.startsWith('https://'));
    const imageUrl = isFullUrl ? response : IMAGE_URL + response;
    setCoverImageUrl(imageUrl);
    form.setFieldsValue({ coverImage: response });
  };
@@ -131,14 +148,19 @@
        // 如果是已存在的图片,从url中提取相对路径
        if (file.url) {
          if (file.url.startsWith(IMAGE_URL)) {
            return file.url.replace(IMAGE_URL, '');
            return file.url.replace(IMAGE_URL, '').replace(/^\/+/, '');
          }
          // 如果是完整URL,直接返回
          if (file.url.startsWith('http://') || file.url.startsWith('https://')) {
            return file.url;
          }
          return file.url;
        }
        return null;
      })
      .filter(Boolean);
    form.setFieldsValue({ carouselImages: urls.join(',') });
    // 将 detailImages 设置为逗号分隔的字符串
    form.setFieldsValue({ detailImages: urls.join(',') });
  };
  // 处理轮播图删除
@@ -152,12 +174,17 @@
          return item.response;
        }
        if (item.url && item.url.startsWith(IMAGE_URL)) {
          return item.url.replace(IMAGE_URL, '');
          return item.url.replace(IMAGE_URL, '').replace(/^\/+/, '');
        }
        // 如果是完整URL,直接返回
        if (item.url && (item.url.startsWith('http://') || item.url.startsWith('https://'))) {
          return item.url;
        }
        return item.url;
      })
      .filter(Boolean);
    form.setFieldsValue({ carouselImages: urls.join(',') });
    // 将 detailImages 设置为逗号分隔的字符串
    form.setFieldsValue({ detailImages: urls.join(',') });
    return true;
  };
@@ -210,9 +237,15 @@
      const submitData = {
        title: values.title,
        coverImage: values.coverImage,
        carouselImages: values.carouselImages || '',
        detailImages: values.detailImages
          ? (typeof values.detailImages === 'string'
            ? values.detailImages
            : Array.isArray(values.detailImages)
              ? values.detailImages.join(',')
              : '')
          : '',
        sortOrder: values.sortOrder || 45,
        homepageDisplay: values.homepageDisplay ? 1 : 0,
        showOnHome: values.showOnHome === true || values.showOnHome === 'true' || values.showOnHome === 1,
        content: announcementContent.content,
      };
@@ -244,7 +277,7 @@
          {/* 公告标题 */}
          <ProFormText
            name="title"
            label="*公告标题"
            label="公告标题"
            placeholder="请输入"
            wrapperCol={{ span: 12 }}
            rules={[{ required: true, message: '请输入公告标题' }]}
@@ -286,9 +319,9 @@
            </Form.Item>
            {/* 详情轮播图 */}
            <Form.Item name="carouselImages" label="详情轮播图">
            <Form.Item name="detailImages" label="详情轮播图">
              <Upload
                name="carouselImages"
                name="detailImages"
                listType="picture-card"
                fileList={carouselImageList}
                beforeUpload={beforeUpload}
@@ -314,7 +347,6 @@
                fieldProps={{
                  style: { width: '120px' },
                }}
                initialValue={45}
              />
              <div style={{ fontSize: '12px', color: '#999', marginTop: '4px', marginLeft: '8px' }}>
                数值越大越靠前
@@ -322,9 +354,9 @@
            </div>
            {/* 是否展示在首页 */}
            <Form.Item name="homepageDisplay" label="是否展示在首页:" style={{ marginBottom: 0 }}>
            <Form.Item name="showOnHome" label="是否展示在首页:" style={{ marginBottom: 0 }}>
              <ProFormSwitch
                name="homepageDisplay"
                name="showOnHome"
                disabled={isReadOnly}
              />
            </Form.Item>
@@ -333,9 +365,9 @@
          {/* 公告内容 */}
          <Form.Item
            name="content"
            label="*公告内容"
            label="公告内容"
            wrapperCol={{ span: 24 }}
            rules={[{ required: true, message: '请输入公告内容' }]}
            // rules={[{ required: true, message: '请输入公告内容' }]}
          >
            <BraftEditorCom
              data={announcementContent.content || ''}
management/src/pages/announcementManagement/index.jsx
@@ -1,30 +1,27 @@
import React, { useRef } from 'react';
import { PageContainer, ProTable } from '@ant-design/pro-components';
import { Button, message, Popconfirm, Image, Space } from 'antd';
import { Button, Image, Space } from 'antd';
import { history } from '@umijs/max';
import { buildProTableDataSource, sendRequest, showDelConfirm } from '@/utils/antdUtils';
import { getAnnouncementList, deleteAnnouncement } from './service';
const AnnouncementManagement = () => {
  const actionRef = useRef();
  // 是否首页展示映射
  const homepageDisplayMap = {
    1: { text: '是' },
    0: { text: '否' },
  const showOnHomeMap = {
    true: { text: '是' },
    false: { text: '否' },
    'true': { text: '是' },
    'false': { text: '否' },
  };
  // 删除公告
  const handleDelete = async (id) => {
    try {
      const res = await deleteAnnouncement(id);
      if (res.code === 200) {
        message.success('删除成功');
        actionRef.current?.reload();
      } else {
        message.error(res.msg || '删除失败');
      }
    } catch (error) {
      message.error('删除失败');
    const status = await sendRequest(deleteAnnouncement, id);
    if (status) {
      actionRef.current?.reload();
    }
  };
@@ -85,10 +82,10 @@
      },
    },
    {
      title: '发布时间',
      dataIndex: 'publishTime',
      valueType: 'date',
      width: 150,
      title: '创建时间',
      dataIndex: 'createTime',
      valueType: 'dateTime',
      width: 180,
      align: 'center',
      hideInTable: false,
      fieldProps: {
@@ -96,20 +93,41 @@
      },
    },
    {
      title: '创建人',
      dataIndex: 'createBy',
      hideInSearch: true,
      width: 120,
      align: 'center',
      ellipsis: true,
    },
    {
      title: '是否首页展示',
      dataIndex: 'homepageDisplay',
      dataIndex: 'showOnHome',
      valueType: 'select',
      hideInTable: true,
      valueEnum: homepageDisplayMap,
      hideInTable: false,
      width: 120,
      align: 'center',
      valueEnum: showOnHomeMap,
      fieldProps: {
        placeholder: '请选择',
      },
      render: (text,record) => {
        return record.showOnHome ? '是' : '否';
      },
    },
    {
      title: '浏览人数',
      dataIndex: 'viewCount',
      dataIndex: 'lookNum',
      hideInSearch: true,
      width: 120,
      align: 'center',
      render: (text) => text || 0,
    },
    {
      title: '排序',
      dataIndex: 'sortOrder',
      hideInSearch: true,
      width: 100,
      align: 'center',
      render: (text) => text || 0,
    },
@@ -128,16 +146,18 @@
          <Button type="link" size="small" onClick={() => handleEdit(record)}>
            编辑
          </Button>
          <Popconfirm
            title="确认删除该公告?"
            onConfirm={() => handleDelete(record.id)}
            okText="确认"
            cancelText="取消"
          <Button
            type="link"
            size="small"
            danger
            onClick={() => {
              showDelConfirm(async () => {
                await handleDelete(record.id);
              }, '删除后不可恢复,请谨慎操作!', '确认', '取消', '确认删除该公告?');
            }}
          >
            <Button type="link" size="small" danger>
              删除
            </Button>
          </Popconfirm>
            删除
          </Button>
        </Space>
      ),
    },
@@ -157,28 +177,21 @@
            新增公告
          </Button>,
        ]}
        request={async (params, sort, filter) => {
          const { current, pageSize, title, publishTime, homepageDisplay, ...rest } = params;
        request={async (params) => {
          const { current, pageSize, title, createTime, showOnHome, ...rest } = params;
          const requestParams = {
            ...rest,
            pageNum: current,
            pageSize,
            title: title || undefined,
            publishTime: publishTime || undefined,
            homepageDisplay: homepageDisplay !== undefined ? homepageDisplay : undefined,
            createTime: createTime || undefined,
            showOnHome: showOnHome !== undefined ? showOnHome : undefined,
          };
          const res = await getAnnouncementList(requestParams);
          return {
            data: (res.data?.records || []).map((item, index) => ({
              ...item,
              index: (current - 1) * pageSize + index + 1,
            })),
            success: res.code === 200,
            total: res.data?.total || 0,
          };
          const result = await buildProTableDataSource(getAnnouncementList, requestParams);
          // 添加序号
          result.data = result.data.map((item, index) => ({
            ...item,
            index: ((current || 1) - 1) * (pageSize || 10) + index + 1,
          }));
          return result;
        }}
        columns={columns}
        scroll={{ x: 1200 }}
management/src/pages/announcementManagement/service.js
@@ -2,7 +2,7 @@
// 获取公告列表(分页)
export async function getAnnouncementList(params) {
  return request('/announcement/page', {
  return request('/t-notice/pageList', {
    method: 'POST',
    data: params,
  });
@@ -10,21 +10,21 @@
// 删除公告
export async function deleteAnnouncement(id) {
  return request(`/announcement/${id}`, {
  return request(`/t-notice/delete/${id}`, {
    method: 'DELETE',
  });
}
// 获取公告详情
export async function getAnnouncementDetail(id) {
  return request(`/announcement/${id}`, {
  return request(`/t-notice/detail/${id}`, {
    method: 'GET',
  });
}
// 新增公告
export async function addAnnouncement(params) {
  return request('/announcement', {
  return request('/t-notice/add', {
    method: 'POST',
    data: params,
  });
@@ -32,8 +32,8 @@
// 编辑公告
export async function editAnnouncement(params) {
  return request('/announcement', {
    method: 'PUT',
  return request('/t-notice/update', {
    method: 'POST',
    data: params,
  });
}
management/src/pages/order/orderList/index.jsx
@@ -1,6 +1,7 @@
import React, { useRef, useState } from 'react';
import { PageContainer, ProTable } from '@ant-design/pro-components';
import { Button, Space, Popconfirm, message } from 'antd';
import { Button, Space } from 'antd';
import { buildProTableDataSource, sendRequest, showDelConfirm } from '@/utils/antdUtils';
import { getPhysicalGoodsOrderList, deletePhysicalGoodsOrder } from './service';
import OrderDetailModal from './components/OrderDetailModal';
import { exportExcell } from '@/utils/utils'
@@ -25,12 +26,9 @@
  // 删除订单
  const handleDelete = async (id) => {
    const res = await deletePhysicalGoodsOrder(id);
    if (res.code === 200) {
      message.success('删除成功');
    const status = await sendRequest(deletePhysicalGoodsOrder, id);
    if (status) {
      actionRef.current?.reload();
    } else {
      message.error(res.message || '删除失败');
    }
  };
@@ -156,11 +154,17 @@
            </Button>
          </Access>
          <Access accessible={access.physicalGoodsOrder_del || false}>
            <Popconfirm title="确认删除?" onConfirm={() => handleDelete(record.id)}>
              <Button type="link" danger>
                删除
              </Button>
            </Popconfirm>
            <Button
              type="link"
              danger
              onClick={() => {
                showDelConfirm(async () => {
                  await handleDelete(record.id);
                }, '删除后不可恢复,请谨慎操作!', '确认', '取消', '确认删除?');
              }}
            >
              删除
            </Button>
          </Access>
        </Space>
      ),
@@ -173,22 +177,14 @@
        actionRef={actionRef}
        columns={columns}
        request={async (params) => {
          const { current, pageSize, ...rest } = params;
          const { ...rest } = params;
          setSearchParams({
            ...rest,
            pageNum: current,
            pageSize,
            pageNum: params.current,
            pageSize: params.pageSize,
          });
          const res = await getPhysicalGoodsOrderList({
            ...rest,
            pageNum: current,
            pageSize,
          });
          return {
            data: res.data?.records || [],
            success: res.code === 200,
            total: res.data?.total || 0,
          };
          const result = await buildProTableDataSource(getPhysicalGoodsOrderList, rest);
          return result;
        }}
        pagination={{
          showQuickJumper: true,
management/src/pages/order/orderList/service.js
@@ -2,7 +2,7 @@
// 获取实物商品订单列表
export async function getPhysicalGoodsOrderList(params) {
  return request('/t-physical-goods-order/pageList', {
  return request('/t-ticket-order/pageList', {
    method: 'POST',
    data: params,
  });
@@ -10,7 +10,7 @@
// 获取实物商品订单详情
export async function getPhysicalGoodsOrderDetail(id) {
  return request(`/t-physical-goods-order/detail/${id}`, {
  return request(`/t-ticket-order/detail/${id}`, {
    method: 'GET',
  });
}
management/src/pages/order/refundAudit/index.jsx
@@ -1,8 +1,8 @@
import { exportExcell } from '@/utils/utils';
import { Button, message, Popconfirm } from 'antd';
import { request } from '@umijs/max';
import { Button } from 'antd';
import { useRef, useState } from 'react';
import { PageContainer, ProTable } from '@ant-design/pro-components';
import { buildProTableDataSource, sendRequest, showDelConfirm } from '@/utils/antdUtils';
import RefundDetailModal from './components/RefundDetailModal';
import { deleteRefundApplication, pageRefundList } from './service';
import { Access, useAccess } from 'umi';
@@ -147,16 +147,18 @@
            </Button>
          </Access>
          <Access accessible={access.refundAudit_del || false}>
            <Popconfirm
              title="确认删除该退款申请?"
              onConfirm={() => handleDelete(record.id)}
              okText="确认"
              cancelText="取消"
            <Button
              type="link"
              size="small"
              danger
              onClick={() => {
                showDelConfirm(async () => {
                  await handleDelete(record.id);
                }, '删除后不可恢复,请谨慎操作!', '确认', '取消', '确认删除该退款申请?');
              }}
            >
              <Button type="link" size="small" danger>
                删除
              </Button>
            </Popconfirm>
              删除
            </Button>
          </Access>
        </>
      ),
@@ -165,16 +167,9 @@
  // 删除退款申请
  const handleDelete = async (id) => {
    try {
      const res = await deleteRefundApplication(id);
      if (res.code === 200) {
        message.success('删除成功');
        actionRef.current?.reload();
      } else {
        message.error(res.msg || '删除失败');
      }
    } catch (error) {
      message.error('删除失败');
    const status = await sendRequest(deleteRefundApplication, id);
    if (status) {
      actionRef.current?.reload();
    }
  };
@@ -199,26 +194,17 @@
        }}
        toolBarRender={false}
        request={async (params) => {
          const { current, pageSize, ...rest } = params;
          const { ...rest } = params;
          // 保存搜索参数,用于导出
          setSearchParams({
            ...rest,
            pageNum: current,
            pageSize,
            pageNum: params.current,
            pageSize: params.pageSize,
          });
          const res = await pageRefundList({
            ...rest,
            pageNum: current,
            pageSize,
          });
          return {
            data: res.data?.records || [],
            success: res.code === 200,
            total: res.data?.total || 0,
          };
          const result = await buildProTableDataSource(pageRefundList, rest);
          return result;
        }}
        columns={columns}
        scroll={{ x: 1600 }}
management/src/pages/order/refundAudit/service.js
@@ -2,7 +2,7 @@
// 获取退款申请列表
export async function pageRefundList(params) {
  return request('/t-refund-application/pageRefundList', {
  return request('/t-ticket-order/refundPageList', {
    method: 'POST',
    data: params,
  });
@@ -24,7 +24,7 @@
// 审核退款申请
export async function refundAudit(params) {
  return request('/t-refund-application/refundAudit', {
  return request('/t-ticket-order/refundAudit', {
    method: 'POST',
    data: params,
  });
management/src/pages/strategyManagement/addAndEdit.jsx
@@ -18,7 +18,7 @@
  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');
@@ -82,44 +82,118 @@
          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);
            }
          }
          // 设置富文本内容
@@ -142,13 +216,55 @@
    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();
      });
  };
  // 处理详情图片上传成功
@@ -276,8 +392,13 @@
    try {
      const values = await form.validateFields();
      console.log('wewqeqwe',detailImageList);
      // 验证封面图
      if (!coverImageUrl) {
      const coverImage = values.coverImage;
      if (!coverImage) {
        message.error('请上传封面图');
        return;
      }
@@ -293,13 +414,50 @@
        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,
      };
@@ -331,7 +489,7 @@
          {/* 攻略标题 */}
          <ProFormText
            name="title"
            label="*攻略标题"
            label="攻略标题"
            placeholder="请输入"
            wrapperCol={{ span: 12 }}
            rules={[{ required: true, message: '请输入攻略标题' }]}
@@ -349,26 +507,15 @@
              <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>
@@ -429,13 +576,12 @@
              <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' }}>
                数值越大越靠前
@@ -446,9 +592,9 @@
          {/* 攻略内容 */}
          <Form.Item
            name="content"
            label="*攻略内容"
            label="攻略内容"
            wrapperCol={{ span: 24 }}
            rules={[{ required: true, message: '请输入攻略内容' }]}
            // rules={[{ required: true, message: '请输入攻略内容' }]}
          >
            <BraftEditorCom
              data={strategyContent.content || ''}
management/src/pages/strategyManagement/index.jsx
@@ -1,7 +1,8 @@
import React, { useRef } from 'react';
import { PageContainer, ProTable } from '@ant-design/pro-components';
import { Button, message, Popconfirm, Image, Space } from 'antd';
import { Button, Image, Space } from 'antd';
import { history } from '@umijs/max';
import { buildProTableDataSource, sendRequest, showDelConfirm } from '@/utils/antdUtils';
import { getStrategyList, deleteStrategy } from './service';
const StrategyManagement = () => {
@@ -9,16 +10,9 @@
  // 删除攻略
  const handleDelete = async (id) => {
    try {
      const res = await deleteStrategy(id);
      if (res.code === 200) {
        message.success('删除成功');
        actionRef.current?.reload();
      } else {
        message.error(res.msg || '删除失败');
      }
    } catch (error) {
      message.error('删除失败');
    const status = await sendRequest(deleteStrategy, id);
    if (status) {
      actionRef.current?.reload();
    }
  };
@@ -79,10 +73,10 @@
      },
    },
    {
      title: '发布时间',
      dataIndex: 'publishTime',
      valueType: 'date',
      width: 150,
      title: '创建时间',
      dataIndex: 'createTime',
      valueType: 'dateTime',
      width: 180,
      align: 'center',
      hideInTable: false,
      fieldProps: {
@@ -90,12 +84,40 @@
      },
    },
    {
      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: '操作',
@@ -112,16 +134,18 @@
          <Button type="link" size="small" onClick={() => handleEdit(record)}>
            编辑
          </Button>
          <Popconfirm
            title="确认删除该攻略?"
            onConfirm={() => handleDelete(record.id)}
            okText="确认"
            cancelText="取消"
          <Button
            type="link"
            size="small"
            danger
            onClick={() => {
              showDelConfirm(async () => {
                await handleDelete(record.id);
              }, '删除后不可恢复,请谨慎操作!', '确认', '取消', '确认删除该攻略?');
            }}
          >
            <Button type="link" size="small" danger>
              删除
            </Button>
          </Popconfirm>
            删除
          </Button>
        </Space>
      ),
    },
@@ -141,27 +165,20 @@
            新增攻略
          </Button>,
        ]}
        request={async (params, sort, filter) => {
          const { current, pageSize, title, publishTime, ...rest } = params;
        request={async (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);
          return {
            data: (res.data?.records || []).map((item, index) => ({
              ...item,
              index: (current - 1) * pageSize + index + 1,
            })),
            success: res.code === 200,
            total: res.data?.total || 0,
          };
          const result = await buildProTableDataSource(getStrategyList, requestParams);
          // 添加序号
          result.data = result.data.map((item, index) => ({
            ...item,
            index: ((current || 1) - 1) * (pageSize || 10) + index + 1,
          }));
          return result;
        }}
        columns={columns}
        scroll={{ x: 1200 }}
management/src/pages/strategyManagement/service.js
@@ -2,7 +2,7 @@
// 获取攻略列表(分页)
export async function getStrategyList(params) {
  return request('/strategy/page', {
  return request('/t-guide/pageList', {
    method: 'POST',
    data: params,
  });
@@ -10,21 +10,21 @@
// 删除攻略
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,
  });
@@ -32,11 +32,13 @@
// 编辑攻略
export async function editStrategy(params) {
  return request('/strategy', {
    method: 'PUT',
  return request('/t-guide/update', {
    method: 'post',
    data: params,
  });
}