董国庆
2026-06-16 01f0d75dbe40254aabfa72fa465b92c3aa38d4f9
Merge branch 'main' of http://120.76.84.145:10101/gitblit/r/H5/qingduTicketing
12个文件已添加
19个文件已修改
2275 ■■■■■ 已修改文件
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 | 历史
miniprogram/config/index.js 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
miniprogram/manifest.json 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
miniprogram/pages.json 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
miniprogram/pages/address/addAddress.vue 229 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
miniprogram/pages/address/address.vue 134 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
miniprogram/pages/invoice/addInvoice.vue 206 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
miniprogram/pages/invoice/applyInvoice.vue 285 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
miniprogram/pages/invoice/invoice.vue 182 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
miniprogram/pages/invoice/invoiceDetail.vue 214 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
miniprogram/pages/login/login.vue 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
miniprogram/pages/mine/mine.vue 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
miniprogram/pages/mineInfo/mineInfo.vue 232 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
miniprogram/pages/tourist/tourist.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
miniprogram/static/image/login/unCheckbox.png 补丁 | 查看 | 原始文档 | blame | 历史
miniprogram/static/image/mine/arrowRight.png 补丁 | 查看 | 原始文档 | blame | 历史
miniprogram/static/image/mine/checked.png 补丁 | 查看 | 原始文档 | blame | 历史
miniprogram/static/image/mine/close.png 补丁 | 查看 | 原始文档 | blame | 历史
miniprogram/static/image/mine/modify.png 补丁 | 查看 | 原始文档 | blame | 历史
miniprogram/static/image/mine/ticket.png 补丁 | 查看 | 原始文档 | 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,
  });
}
miniprogram/config/index.js
@@ -1,6 +1,6 @@
export default {
    // BASE_URL: 'http://192.168.110.188:9100',
    BASE_URL: 'https://jiashikang.cn/applet',
    BASE_URL: 'http://192.168.110.111:9100',
    // BASE_URL: 'https://jiashikang.cn/applet',
    uploadUrl: "https://jiashikang.cn/applet/open/file/upload",
    imageUrl: 'https://jiashikang.cn/images/'
};
miniprogram/manifest.json
@@ -1,7 +1,7 @@
{
    "sassImplementationName" : "node-sass",
    "name" : "青城后山",
    "appid" : "__UNI__E5BD0E6",
    "appid" : "__UNI__B98B5B1",
    "description" : "",
    "versionName" : "1.0.0",
    "versionCode" : "100",
miniprogram/pages.json
@@ -136,6 +136,43 @@
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/invoice/invoice",
            "style": {
                "navigationBarTitleText": "发票管理"
            }
        },
        {
            "path": "pages/invoice/addInvoice",
            "style": {
                "navigationBarTitleText": "我要开票"
            }
        },
        {
            "path": "pages/invoice/invoiceDetail",
            "style": {
                "navigationBarTitleText": "发票详情",
                "navigationStyle": "custom"
            }
        },
        {
            "path": "pages/invoice/applyInvoice",
            "style": {
                "navigationBarTitleText": "申请开票"
            }
        },
        {
            "path": "pages/address/addAddress",
            "style": {
                "navigationBarTitleText": "新增收货地址"
            }
        },
        {
            "path": "pages/address/address",
            "style": {
                "navigationBarTitleText": "收货地址"
            }
        }
    ],
    "subPackages": [{
miniprogram/pages/address/addAddress.vue
New file
@@ -0,0 +1,229 @@
<template>
    <view class="container pt-19">
        <u-form :model="form" ref="uFormRef" :rules="rules" label-position="top">
            <u-form-item label="姓名" prop="name">
                <u-input v-model="form.name" placeholder-style="font-size: 23rpx; color: rgba(0, 0, 0, 0.45);"
                    placeholder="请输入" />
            </u-form-item>
            <u-form-item label="电话" prop="phone">
                <u-input v-model="form.phone" placeholder-style="font-size: 23rpx; color: rgba(0, 0, 0, 0.45);"
                    placeholder="请输入" />
            </u-form-item>
            <u-form-item label="地区" prop="address">
                <view class="flex a-center j-between address" @click="selectAddress">
                    <text v-if="form.address">{{ form.address }}</text>
                    <text v-else style="color: rgba(0,0,0,0.25);">请选择</text>
                    <image src="/static/image/mine/arrowRight.png" class="w-23 h-23"></image>
                </view>
            </u-form-item>
            <u-form-item label="详细地址" prop="detailAddress">
                <u-input v-model="form.detailAddress" placeholder-style="font-size: 23rpx; color: rgba(0, 0, 0, 0.45);"
                    placeholder="请输入" />
            </u-form-item>
            <u-form-item label="设为默认地址" prop="isDefault" :border-bottom="false" label-position="left"
                :label-width="215">
                <view class="flex a-center j-end" @click="form.isDefault = !form.isDefault">
                    <image src="/static/image/login/unCheckbox.png" class="w-35 h-35" v-if="!form.isDefault"></image>
                    <image src="/static/image/login/checkbox.png" class="w-35 h-35" v-else></image>
                </view>
            </u-form-item>
        </u-form>
        <view class="footer">
            <view class="w100 h100 flex a-center j-center" v-if="id">
                <view class="delete-btn">
                    删除游客信息
                </view>
                <view class="btn" @click="submit">
                    保存
                </view>
            </view>
            <view class="w100 h100 flex a-center j-center" v-else>
                <view class="btn save-btn" @click="submit">
                    保存
                </view>
            </view>
        </view>
    </view>
    <!-- <u-popup v-model="show" mode="bottom" :safe-area-inset-bottom="true" border-radius="20" :closeable="false"
        @close="show = false">
        <view class="asset-type-popup">
            <view class="flex a-center j-between pl-4 pr-6 mb-40">
                <view class="popup-title">选择地区</view>
                <u-image width="34.62rpx" height="34.62rpx" class="shrink0" src="@/static/image/mine/close.png"
                    @click="show = false"></u-image>
            </view>
            <view class="picker-container">
                <picker-view :value="pickerValue" :indicator-style="indicatorStyle" @change="onPickerChange"
                    class="picker-view">
                    <picker-view-column>
                        <view class="picker-item" v-for="(item, index) in columns" :key="index">
                            {{ item.label ?? item.text }}
                        </view>
                    </picker-view-column>
                </picker-view>
            </view>
            <view class="popup-footer mb-38">
                <view class="submit-btn" @click="handleConfirm">确定</view>
            </view>
        </view>
    </u-popup> -->
</template>
<script setup lang="ts">
import { ref, reactive } from "vue";
import { onLoad } from "@dcloudio/uni-app";
const uFormRef = ref();
const form = reactive({
    name: '',
    phone: '',
    address: '',
    detailAddress: '',
    isDefault: false,
});
const show = ref(false);
const id = ref('');
const rules = {
    name: [
        {
            required: true,
            message: '请输入姓名',
            trigger: ['change', 'blur']
        }
    ],
    phone: [
        {
            required: true,
            message: '请输入联系电话',
            trigger: ['change', 'blur']
        }
    ]
    ,
    address: [
        {
            required: true,
            message: '请输入详细地址',
            trigger: ['change', 'blur']
        }
    ]
};
const selectAddress = () => {
    show.value = true;
}
const handleConfirm = () => {
}
function submit() {
    uFormRef.value?.validate((valid: boolean) => {
        if (valid) {
        } else {
            console.log('验证失败');
        }
    });
}
onLoad((options) => {
    id.value = options.id || '';
})
</script>
<style>
page {
    background-color: #fff !important;
    height: 100%;
}
</style>
<style scoped lang="scss">
.container {
    width: 100%;
    height: 100%;
    box-sizing: border-box;
    position: relative;
    :deep(.u-form) {
        padding: 0 27rpx;
        --u-border-color: rgba(0, 0, 0, 0.06);
        .u-form-item {
            padding: 20rpx 0;
        }
        .u-form-item--left {
            margin-bottom: 20rpx !important;
        }
    }
    :deep(.u-form-item) {
        .u-form-item--left__content__label {
            font-family: PingFangSC, PingFang SC;
            font-weight: 600;
            font-size: 27rpx;
            color: rgba(0, 0, 0, 0.85);
            line-height: 38rpx;
        }
        .u-input {
            padding-right: 16rpx !important;
        }
    }
    .address {
        font-family: PingFang-SC, PingFang-SC;
        font-weight: 500;
        font-size: 27rpx;
        line-height: 42rpx;
    }
    .footer {
        width: 100%;
        height: 173rpx;
        background: #FFFFFF;
        border-top: 2rpx solid rgba(0, 0, 0, 0.06);
        position: absolute;
        bottom: 83rpx;
        left: 0;
        .delete-btn {
            width: 250rpx;
            height: 96rpx;
            border-radius: 58rpx;
            border: 2rpx solid #06C584;
            margin-left: 27rpx;
            margin-right: 27rpx;
            display: flex;
            align-items: center;
            justify-content: center;
            font-family: PingFangSC, PingFang SC;
            font-weight: 500;
            font-size: 31rpx;
            color: #06C584;
            line-height: 42rpx;
        }
        .btn {
            width: 419rpx;
            height: 96rpx;
            background: linear-gradient(270deg, #08C866 0%, #06C584 100%);
            box-shadow: 0rpx 8rpx 19rpx 0rpx rgba(6, 197, 132, 0.19);
            border-radius: 67rpx;
            display: flex;
            align-items: center;
            justify-content: center;
            font-family: PingFangSC, PingFang SC;
            font-weight: 500;
            font-size: 31rpx;
            color: #FFFFFF;
            line-height: 42rpx;
        }
        .save-btn {
            width: 596rpx;
        }
    }
}
</style>
miniprogram/pages/address/address.vue
New file
@@ -0,0 +1,134 @@
<template>
    <view class="container px-27 pt-31">
        <view class="list">
            <view v-for="(item, index) in list" :key="index" class="item">
                <view class="flex a-center mb-27">
                    <view class="name mr-54">{{ item.name }}</view>
                    <view class="phone">{{ item.phone }}</view>
                </view>
                <view class="address">{{ item.address }}</view>
                <image src="../../static/image/mine/modify.png" class="w-35 h-35"
                    @click.stop="toAddTourist(item.id)"></image>
                <view v-if="item.isDefault" class="default active">默认</view>
                <view v-else class="default">设为默认</view>
            </view>
        </view>
        <view class="add flex a-center j-center" @click="toAddTourist">
            新增地址
        </view>
    </view>
</template>
<script setup lang="ts">
import { ref } from "vue";
const list = ref([
    {
        id: 1,
        name: '张三',
        phone: '13812340000',
        address: '河北省秦皇岛市青龙满族自治县珠江大道965号',
        isDefault: true,
    },
    {
        id: 2,
        name: '李四',
        phone: '13812340001',
        address: '河北省秦皇岛市青龙满族自治县珠江大道965号',
        isDefault: false,
    }
])
const toAddTourist = (id?: any) => {
    uni.navigateTo({
        url: '/pages/address/addAddress?id=' + id,
    })
}
</script>
<style>
page {
    height: 100%;
}
</style>
<style scoped lang="scss">
.container {
    width: 100%;
    height: 100%;
    box-sizing: border-box;
    position: relative;
    .add {
        width: 596rpx;
        height: 96rpx;
        background: linear-gradient(270deg, #08C866 0%, #06C584 100%);
        box-shadow: 0rpx 4rpx 25rpx 0rpx rgba(6, 197, 132, 0.15), 0rpx 8rpx 19rpx 0rpx rgba(6, 197, 132, 0.19);
        border-radius: 67rpx;
        font-family: PingFangSC, PingFang SC;
        font-weight: 600;
        font-size: 35rpx;
        color: #FFFFFF;
        line-height: 48rpx;
        text-shadow: 0px 4px 25px rgba(6, 197, 132, 0.15);
        position: absolute;
        bottom: 108rpx;
        left: 77rpx;
    }
    .list {
        .item {
            width: 696rpx;
            // height: 142rpx;
            background: #fff;
            border-radius: 19rpx;
            margin-top: 27rpx;
            padding: 27rpx;
            box-sizing: border-box;
            position: relative;
            image {
                position: absolute;
                bottom: 42rpx;
                right: 27rpx;
            }
            .name,
            .phone {
                font-family: Plumb, Plumb;
                font-weight: bold;
                font-size: 31rpx;
                color: #303133;
                line-height: 27rpx;
            }
            .address {
                width: 535rpx;
                font-family: PingFang-SC, PingFang-SC;
                font-weight: 500;
                font-size: 27rpx;
                color: rgba(0, 0, 0, 0.65);
                line-height: 38rpx;
            }
            .default {
                position: absolute;
                top: 0;
                right: 0;
                padding: 6rpx 19rpx 6rpx 15rpx;
                background: rgba(6, 197, 132, 0.19);
                border-radius: 0rpx 19rpx 0rpx 19rpx;
                font-family: PingFangSC, PingFang SC;
                font-weight: 600;
                font-size: 23rpx;
                color: #303133;
                line-height: 33rpx;
                display: flex;
                align-items: center;
                justify-content: center;
            }
            .active {
                background: #06C584;
                color: #fff;
            }
        }
    }
}
</style>
miniprogram/pages/invoice/addInvoice.vue
New file
@@ -0,0 +1,206 @@
<template>
    <view class="container pt-19">
        <view class="px-27">
            <view class="list-item" v-for="(item, index) in invoiceList" :key="index"
                @click="item.checked = !item.checked">
                <image src="/static/image/login/unCheckbox.png" class="w-35 h-35" v-if="!item.checked"></image>
                <image src="/static/image/login/checkbox.png" class="w-35 h-35" v-else></image>
                <view class="flex p-31 ml-35 box">
                    <image :src="item.img" class="w-231 h-154 mr-19"></image>
                    <view>
                        <view class="name mt-12">{{ item.name || '' }}</view>
                        <view class="flex a-center mb-12">
                            <view class="label">下单时间</view>
                            <view class="value">{{ item.time || '' }}</view>
                        </view>
                        <view class="flex a-center">
                            <view class="label">总价</view>
                            <view class="value"><text>¥</text>{{ item.price || '' }}</view>
                        </view>
                    </view>
                </view>
            </view>
        </view>
        <view class="footer flex j-between a-center">
            <view class="flex a-center">
                <view class="total">总额</view>
                <view class="price"><text>¥ </text>8889</view>
            </view>
            <view class="btn flex j-center a-center" @click="submit">去申请</view>
        </view>
    </view>
</template>
<script setup lang="ts">
import { ref } from "vue";
import { onLoad, onUnload, onShow, onReachBottom } from "@dcloudio/uni-app";
const invoiceList = ref([
    {
        time: '2023-08-01',
        name: '成人票',
        price: '100.00',
        img: '/static/image/mine/contact.png',
        checked: false
    }
]);
const finished = ref(false);
const loading = ref(false);
const searchParams = ref({
    pageNum: 1,
    pageSize: 10
})
const submit = () => {
    uni.navigateTo({
        url: '/pages/invoice/applyInvoice',
    })
}
const fetchList = () => {
    //         // if (loading.value || finished.value) return
    //         loading.value = true
    //         getMonitorList({
    //             nameOrCode: keyword.value || '',
    //             pageNum: searchParams.value.pageNum,
    //             pageSize: searchParams.value.pageSize
    //         }).then(res => {
    //             // PC 端类型定义:{ records, total, current, size }
    //             const data = res.data || res || {}
    //             const records = data.records || []
    //             const total = data.total || 0
    //             if (searchParams.value.pageNum === 1) {
    //                 list.value = records
    //             } else {
    //                 list.value = list.value.concat(records)
    //             }
    //             // 判断是否已全部加载
    //             if (!records.length || list.value.length >= total) {
    //                 finished.value = true
    //             } else {
    //                 searchParams.value.pageNum += 1
    //             }
    //         }).catch(() => {
    //             uni.showToast({
    //                 title: '获取巡检列表失败',
    //                 icon: 'none'
    //             })
    //         }).finally(() => {
    //             loading.value = false
    //         })
}
onReachBottom(() => {
})
</script>
<style>
page {
    background-color: #FFFFFF;
    height: 100%;
}
</style>
<style scoped lang="scss">
.container {
    width: 100%;
    height: 100%;
    position: relative;
    .footer {
        width: 100%;
        background: #FFFFFF;
        box-shadow: 0rpx -8rpx 15rpx 0rpx rgba(0, 0, 0, 0.06);
        position: absolute;
        bottom: 0;
        left: 0;
        padding: 0 27rpx 0;
        padding-top: 29rpx;
        padding-bottom: 0;
        padding-bottom: constant(safe-area-inset-bottom);
        padding-bottom: env(safe-area-inset-bottom);
        .total {
            font-family: PingFangSC, PingFang SC;
            font-weight: 600;
            font-size: 27rpx;
            color: rgba(0, 0, 0, 0.85);
            line-height: 38rpx;
            margin-right: 12rpx;
        }
        .price {
            font-family: PingFangSC, PingFang SC;
            font-weight: 600;
            font-size: 58rpx;
            color: #FF6257;
            line-height: 54rpx;
            text {
                font-size: 38rpx;
            }
        }
        .btn {
            width: 327rpx;
            height: 96rpx;
            background: linear-gradient(270deg, #08C866 0%, #06C584 100%);
            box-shadow: 0rpx 4rpx 25rpx 0rpx rgba(6, 197, 132, 0.15), 0rpx 8rpx 19rpx 0rpx rgba(6, 197, 132, 0.19);
            border-radius: 67rpx;
            font-family: PingFangSC, PingFang SC;
            font-weight: 600;
            font-size: 35rpx;
            color: #FFFFFF;
            line-height: 48rpx;
            text-shadow: 0px 4px 25px rgba(6, 197, 132, 0.15);
        }
    }
    .list-item {
        margin-top: 27rpx;
        display: flex;
        align-items: center;
        .box {
            flex: 1;
            height: 215rpx;
            background: #FFFFFF;
            border: 2rpx solid rgba(6, 197, 132, 0.2);
            border-radius: 19rpx;
            image {
                border-radius: 19rpx;
            }
        }
        .name {
            font-family: PingFangSC, PingFang SC;
            font-weight: 600;
            font-size: 38rpx;
            color: rgba(0, 0, 0, 0.85);
            line-height: 46rpx;
            margin-bottom: 19rpx;
        }
        .label {
            width: 138rpx;
            font-family: PingFangSC, PingFang SC;
            font-weight: 500;
            font-size: 23rpx;
            color: rgba(0, 0, 0, 0.65);
            line-height: 33rpx;
        }
        .value {
            font-family: PingFangSC, PingFang SC;
            font-weight: 600;
            font-size: 23rpx;
            color: #191F3F;
            line-height: 33rpx;
        }
    }
}
</style>
miniprogram/pages/invoice/applyInvoice.vue
New file
@@ -0,0 +1,285 @@
<template>
    <view class="container">
        <view class="flex a-center box flex p-31">
            <image :src="invoice.img" class="w-231 h-154 mr-19"></image>
            <view>
                <view class="name mt-12">{{ invoice.name || '' }}</view>
                <view class="flex a-center mb-12">
                    <view class="label">下单时间</view>
                    <view class="value">{{ invoice.time || '' }}</view>
                </view>
                <view class="flex a-center">
                    <view class="label">总价</view>
                    <view class="value"><text>¥</text>{{ invoice.price || '' }}</view>
                </view>
            </view>
            <view class="default">订单一</view>
        </view>
        <view class="box1">
            <u-form :model="form" ref="uFormRef" :rules="rules" label-position="top">
                <u-form-item label="发票金额" prop="invoiceAmount">
                    <view class="price"><text>¥ </text>{{ invoice.price || '' }}</view>
                </u-form-item>
                <u-form-item label="抬头类型" prop="invoiceType">
                    <view class="invoiceType flex a-center">
                        <view class="item flex a-center j-center" :class="{ 'active': form.invoiceType === 1 }"
                            @click="form.invoiceType = 1">公司<image v-if="form.invoiceType === 1"
                                src="/static/image/mine/checked.png" class="w-33 h-25">
                            </image>
                        </view>
                        <view class="item flex a-center j-center" :class="{ 'active': form.invoiceType === 2 }"
                            @click="form.invoiceType = 2">个人<image v-if="form.invoiceType === 2"
                                src="/static/image/mine/checked.png" class="w-33 h-25">
                            </image>
                        </view>
                    </view>
                </u-form-item>
                <u-form-item label="公司抬头" prop="companyName">
                    <u-input v-model="form.companyName"
                        placeholder-style="font-size: 23rpx; color: rgba(0, 0, 0, 0.45);" placeholder="必填" />
                </u-form-item>
                <u-form-item label="公司税号" prop="companyTaxNumber">
                    <u-input v-model="form.companyTaxNumber"
                        placeholder-style="font-size: 23rpx; color: rgba(0, 0, 0, 0.45);" placeholder="必填" />
                </u-form-item>
                <u-form-item label="接收邮箱" prop="email" :border-bottom="false">
                    <u-input v-model="form.email" placeholder-style="font-size: 23rpx; color: rgba(0, 0, 0, 0.45);"
                        placeholder="必填" />
                </u-form-item>
            </u-form>
        </view>
        <view class="tips">注:提交后将不可修改,请仔细检查过后提交。</view>
        <view class="btn flex a-center j-center" @click="submit">提交申请</view>
    </view>
</template>
<script setup lang="ts">
import { ref, reactive } from "vue";
import { onLoad, onUnload, onShow } from "@dcloudio/uni-app";
const uFormRef = ref();
const form = reactive({
    companyName: '',
    companyTaxNumber: '',
    email: '',
    invoiceType: 1
});
const rules = {
    companyName: [
        {
            required: true,
            message: '请输入公司抬头',
            trigger: ['change', 'blur']
        }
    ],
    companyTaxNumber: [
        {
            required: true,
            message: '请输入公司税号',
            trigger: ['change', 'blur']
        }
    ],
    email: [
        {
            required: true,
            message: '请输入接收邮箱',
            trigger: ['change', 'blur']
        }
    ]
    ,
};
const invoice = ref(
    {
        time: '2023-08-01',
        name: '成人票',
        price: '100.00',
        img: '/static/image/mine/contact.png',
        checked: false
    }
);
function submit() {
    uFormRef.value?.validate((valid: boolean) => {
        if (valid) {
        } else {
            console.log('验证失败');
        }
    });
}
</script>
<style>
page {
    background-color: #FFFFFF;
    height: 100%;
}
</style>
<style scoped lang="scss">
.container {
    width: 100%;
    height: 100%;
    position: relative;
    padding: 0 27rpx;
    padding-top: 37rpx;
    box-sizing: border-box;
    .box {
        width: 100%;
        height: 215rpx;
        background: #FFFFFF;
        border: 2rpx solid rgba(6, 197, 132, 0.2);
        border-radius: 19rpx;
        position: relative;
        image {
            border-radius: 19rpx;
        }
        .default {
            position: absolute;
            top: -10rpx;
            right: -6rpx;
            padding: 6rpx 19rpx 6rpx 15rpx;
            border-radius: 0rpx 19rpx 0rpx 19rpx;
            font-family: PingFangSC, PingFang SC;
            font-weight: 600;
            font-size: 23rpx;
            line-height: 33rpx;
            display: flex;
            align-items: center;
            justify-content: center;
            background: #06C584;
            color: #fff;
        }
        .name {
            font-family: PingFangSC, PingFang SC;
            font-weight: 600;
            font-size: 38rpx;
            color: rgba(0, 0, 0, 0.85);
            line-height: 46rpx;
            margin-bottom: 19rpx;
        }
        .label {
            width: 138rpx;
            font-family: PingFangSC, PingFang SC;
            font-weight: 500;
            font-size: 23rpx;
            color: rgba(0, 0, 0, 0.65);
            line-height: 33rpx;
        }
        .value {
            font-family: PingFangSC, PingFang SC;
            font-weight: 600;
            font-size: 23rpx;
            color: #191F3F;
            line-height: 33rpx;
        }
    }
    .box1 {
        width: 100%;
        background: #FFFFFF;
        border: 2rpx solid rgba(6, 197, 132, 0.2);
        border-radius: 19rpx;
        margin-top: 27rpx;
        .price {
            font-family: PingFangSC, PingFang SC;
            font-weight: 600;
            font-size: 38rpx;
            color: #303133;
            line-height: 38rpx;
            text {
                font-size: 27rpx;
            }
        }
        .invoiceType {
            .item {
                width: 154rpx;
                height: 62rpx;
                background: #F8F8F8;
                border-radius: 19rpx;
                font-family: PingFang-SC, PingFang-SC;
                font-weight: 500;
                font-size: 27rpx;
                color: #191F3F;
                line-height: 38rpx;
                margin-right: 35rpx;
                position: relative;
                image {
                    position: absolute;
                    top: 0;
                    right: 0;
                }
            }
        }
        .item.active {
            background: rgba(6, 197, 132, 0.1);
            color: #06C584;
        }
        :deep(.u-form) {
            padding-left: 27rpx;
            --u-border-color: rgba(0, 0, 0, 0.06);
            .u-form-item--left {
                margin-bottom: 27rpx !important;
            }
        }
        :deep(.u-form-item) {
            .u-form-item--left__content__label {
                font-family: PingFangSC, PingFang SC;
                font-weight: 600;
                font-size: 27rpx;
                color: rgba(0, 0, 0, 0.85);
                line-height: 38rpx;
            }
            .u-input {
                padding-right: 16rpx !important;
            }
        }
    }
    .tips {
        font-family: PingFangSC, PingFang SC;
        font-weight: 600;
        font-size: 23rpx;
        color: #00AD72;
        line-height: 35rpx;
        text-align: center;
        margin-top: 19rpx;
        margin-bottom: 56rpx;
    }
    .btn {
        width: 596rpx;
        height: 96rpx;
        background: linear-gradient(270deg, #08C866 0%, #06C584 100%);
        box-shadow: 0rpx 4rpx 25rpx 0rpx rgba(6, 197, 132, 0.15), 0rpx 8rpx 19rpx 0rpx rgba(6, 197, 132, 0.19);
        border-radius: 67rpx;
        font-family: PingFangSC, PingFang SC;
        font-weight: 600;
        font-size: 35rpx;
        color: #FFFFFF;
        line-height: 48rpx;
        text-shadow: 0px 4px 25px rgba(6, 197, 132, 0.15);
        margin: 0 auto;
    }
}
</style>
miniprogram/pages/invoice/invoice.vue
New file
@@ -0,0 +1,182 @@
<template>
    <view class="container">
        <view class="head flex a-center j-between">
            <view>开票记录</view>
            <view class="flex a-center invoice" @click="toAdd">我要开票 <image src="/static/image/mine/arrowRight.png" class="w-23 h-23">
                </image>
            </view>
        </view>
        <view class="px-27">
            <view class="list-item" v-for="(item, index) in invoiceList" :key="index"  @click="toDetail(item)">
                <view class="flex a-center j-between">
                    <view class="time">{{ item.time || '' }}</view>
                    <view class="status flex a-center j-center">开票中</view>
                </view>
                <view class="flex a-center j-between">
                    <view class="name">{{ item.name || '' }}</view>
                    <view class="price"><text>¥ </text>{{ item.price || '' }}</view>
                </view>
            </view>
        </view>
    </view>
</template>
<script setup lang="ts">
import { ref } from "vue";
import { onLoad, onUnload, onShow, onReachBottom } from "@dcloudio/uni-app";
const invoiceList = ref([
    {
        time: '2023-08-01 10:00:00',
        name: '成人票',
        price: '100.00'
    }
]);
const finished = ref(false);
const loading = ref(false);
const searchParams = ref({
    pageNum: 1,
    pageSize: 10
})
const toAdd = () => {
    uni.navigateTo({
        url: '/pages/invoice/addInvoice',
    })
}
const toDetail = (item) => {
    uni.navigateTo({
        url: '/pages/invoice/invoiceDetail?id=' + item.id,
    })
}
const fetchList = () => {
    //         // if (loading.value || finished.value) return
    //         loading.value = true
    //         getMonitorList({
    //             nameOrCode: keyword.value || '',
    //             pageNum: searchParams.value.pageNum,
    //             pageSize: searchParams.value.pageSize
    //         }).then(res => {
    //             // PC 端类型定义:{ records, total, current, size }
    //             const data = res.data || res || {}
    //             const records = data.records || []
    //             const total = data.total || 0
    //             if (searchParams.value.pageNum === 1) {
    //                 list.value = records
    //             } else {
    //                 list.value = list.value.concat(records)
    //             }
    //             // 判断是否已全部加载
    //             if (!records.length || list.value.length >= total) {
    //                 finished.value = true
    //             } else {
    //                 searchParams.value.pageNum += 1
    //             }
    //         }).catch(() => {
    //             uni.showToast({
    //                 title: '获取巡检列表失败',
    //                 icon: 'none'
    //             })
    //         }).finally(() => {
    //             loading.value = false
    //         })
}
onReachBottom(() => {
})
</script>
<style scoped lang="scss">
.container {
    width: 100%;
    height: 100%;
    position: relative;
    .head {
        width: 100%;
        height: 96rpx;
        background: #FFFFFF;
        box-shadow: 0rpx 6rpx 6rpx 0rpx rgba(0, 0, 0, 0.05);
        position: sticky;
        top: 0;
        left: 0;
        padding: 0 27rpx;
        box-sizing: border-box;
        font-family: PingFangSC, PingFang SC;
        font-weight: 600;
        font-size: 31rpx;
        color: #303133;
        line-height: 42rpx;
        text-shadow: 0px 6px 6px rgba(0, 0, 0, 0.05);
        .invoice {
            font-family: PingFangSC, PingFang SC;
            font-weight: 500;
            font-size: 27rpx;
            color: #4F4F4F;
            line-height: 38rpx;
            text-shadow: 0px 6px 6px rgba(0, 0, 0, 0.05);
        }
        image {
            margin-left: 12rpx;
        }
    }
    .list-item {
        margin-top: 27rpx;
        width: 696rpx;
        height: 173rpx;
        background: #FFFFFF;
        border-radius: 19rpx;
        padding: 25rpx 31rpx;
        .time {
            font-family: PingFangSC, PingFang SC;
            font-weight: 500;
            font-size: 23rpx;
            color: #8C8C8C;
            line-height: 23rpx;
        }
        .status {
            width: 104rpx;
            height: 46rpx;
            background: #D9FFF2;
            border-radius: 12rpx;
            font-family: PingFangSC, PingFang SC;
            font-weight: 600;
            font-size: 25rpx;
            color: #06C584;
            line-height: 23rpx;
            letter-spacing: 1px;
            margin-bottom: 17rpx;
        }
        .name {
            font-family: PingFangSC, PingFang SC;
            font-weight: 600;
            font-size: 38rpx;
            color: #303133;
            line-height: 54rpx;
        }
        .price {
            font-family: PingFangSC, PingFang SC;
            font-weight: 600;
            font-size: 38rpx;
            color: #FF6257;
            line-height: 38rpx;
            text {
                font-size: 27rpx;
            }
        }
    }
}
</style>
miniprogram/pages/invoice/invoiceDetail.vue
New file
@@ -0,0 +1,214 @@
<template>
    <view class="container">
        <u-navbar title="发票信息" :border-bottom="false" background="transparent" :is-fixed="false" title-bold></u-navbar>
        <view class="px-27">
            <view class="title">开票中</view>
            <view class="flex a-center box flex p-31 mt-38">
                <image :src="invoice.img" class="w-231 h-154 mr-19"></image>
                <view>
                    <view class="name mt-12">{{ invoice.name || '' }}</view>
                    <view class="flex a-center mb-12">
                        <view class="label">下单时间</view>
                        <view class="value">{{ invoice.time || '' }}</view>
                    </view>
                    <view class="flex a-center">
                        <view class="label">总价</view>
                        <view class="value"><text>¥</text>{{ invoice.price || '' }}</view>
                    </view>
                </view>
                <view class="default">订单一</view>
            </view>
            <view class="box1 mt-27"
                style="background: url('../../static/image/mine/ticket.png');background-size: 100% 100%">
                <view class="name mb-58">成都市文景智旅网络科技有限公司</view>
                <view class="flex a-center j-between mb-21">
                    <view class="label">发票金额</view>
                    <view class="value">¥240</view>
                </view>
                <view class="flex a-center j-between mb-21">
                    <view class="label">发票内容</view>
                    <view class="value">景点门票费</view>
                </view>
                <view class="flex a-center j-between">
                    <view class="label">申请时间</view>
                    <view class="value">2025-09-09 11:00:00</view>
                </view>
            </view>
            <view class="box2 mt-27 flex a-center">
                <view class="flex a-center j-between w100">
                    <view class="label">接收邮箱</view>
                    <view class="value">debtib@rolovtoc.co</view>
                </view>
            </view>
        </view>
        <view class="btn flex a-center j-center" @click="viewInvoice">查看发票</view>
    </view>
</template>
<script setup lang="ts">
import { ref, } from "vue";
import { onLoad, onUnload, onShow } from "@dcloudio/uni-app";
const invoice = ref(
    {
        time: '2023-08-01',
        name: '成人票',
        price: '100.00',
        img: '/static/image/mine/contact.png',
        checked: false
    }
);
const viewInvoice = () => {
}
</script>
<style>
page {
    background-color: #FFFFFF;
    height: 100%;
}
</style>
<style scoped lang="scss">
.container {
    width: 100%;
    height: 100%;
    position: relative;
    box-sizing: border-box;
    background: linear-gradient(180deg, rgba(6, 197, 132, 0.4) 0%, rgba(6, 197, 132, 0) 317rpx);
    .title {
        margin-top: 23rpx;
        font-family: PingFangSC, PingFang SC;
        font-weight: 600;
        font-size: 46rpx;
        color: #303133;
        line-height: 63rpx;
    }
    .box {
        width: 100%;
        height: 215rpx;
        background: #FFFFFF;
        border: 2rpx solid rgba(6, 197, 132, 0.2);
        border-radius: 19rpx;
        position: relative;
        image {
            border-radius: 19rpx;
        }
        .default {
            position: absolute;
            top: -10rpx;
            right: -6rpx;
            padding: 6rpx 19rpx 6rpx 15rpx;
            border-radius: 0rpx 19rpx 0rpx 19rpx;
            font-family: PingFangSC, PingFang SC;
            font-weight: 600;
            font-size: 23rpx;
            line-height: 33rpx;
            display: flex;
            align-items: center;
            justify-content: center;
            background: #06C584;
            color: #fff;
        }
        .name {
            font-family: PingFangSC, PingFang SC;
            font-weight: 600;
            font-size: 38rpx;
            color: rgba(0, 0, 0, 0.85);
            line-height: 46rpx;
            margin-bottom: 19rpx;
        }
        .label {
            width: 138rpx;
            font-family: PingFangSC, PingFang SC;
            font-weight: 500;
            font-size: 23rpx;
            color: rgba(0, 0, 0, 0.65);
            line-height: 33rpx;
        }
        .value {
            font-family: PingFangSC, PingFang SC;
            font-weight: 600;
            font-size: 23rpx;
            color: #191F3F;
            line-height: 33rpx;
        }
    }
    .box1 {
        padding: 29rpx 31rpx;
        .name {
            font-family: PingFangSC, PingFang SC;
            font-weight: 500;
            font-size: 27rpx;
            color: #191F3F;
            line-height: 38rpx;
        }
        .label {
            font-family: PingFang-SC, PingFang-SC;
            font-weight: 500;
            font-size: 27rpx;
            color: rgba(0, 0, 0, 0.65);
            line-height: 38rpx;
        }
        .value {
            font-family: PingFangSC, PingFang SC;
            font-weight: 600;
            font-size: 27rpx;
            color: #191F3F;
            line-height: 38rpx;
        }
    }
    .box2 {
        width: 696rpx;
        height: 115rpx;
        background: #FFFFFF;
        border: 2rpx solid rgba(6, 197, 132, 0.2);
        padding: 0 31rpx;
        box-sizing: border-box;
        border-radius: 19rpx;
        .label {
            font-family: PingFang-SC, PingFang-SC;
            font-weight: 500;
            font-size: 27rpx;
            color: rgba(0, 0, 0, 0.65);
            line-height: 38rpx;
        }
        .value {
            font-family: PingFangSC, PingFang SC;
            font-weight: 600;
            font-size: 27rpx;
            color: #191F3F;
            line-height: 38rpx;
        }
    }
    .btn {
        width: 327rpx;
        height: 96rpx;
        border-radius: 58rpx;
        border: 2rpx solid #06C584;
        font-family: PingFangSC, PingFang SC;
        font-weight: 500;
        font-size: 31rpx;
        color: #06C584;
        line-height: 42rpx;
        position: absolute;
        left: 212rpx;
        bottom: 117rpx;
    }
}
</style>
miniprogram/pages/login/login.vue
@@ -62,7 +62,7 @@
    const isChecked = ref<boolean>(false);
    const jsCode = ref<string>("");
    const loginType = ref<boolean>(false);
    const loginType = ref<boolean>(true);
    const msgFlag = ref<boolean>(false);
    const time = ref<number>(0);
    const timer = ref<any>(null);
@@ -125,9 +125,9 @@
                                icon: 'none',
                                mask: true
                            })
                            if (inviteInfo.value.id) {
                                confirmSuperior({ superiorType: inviteInfo.value.type, superiorId: inviteInfo.value.id })
                            }
                            // if (inviteInfo.value.id) {
                            //     confirmSuperior({ superiorType: inviteInfo.value.type, superiorId: inviteInfo.value.id })
                            // }
                            uni.setStorageSync('token', res.data?.token)
                            uni.setStorageSync('userInfo', res.data?.info)
                            setTimeout(() => {
@@ -147,7 +147,8 @@
            loginType.value = true;
            return;
        }
        uni.navigateBack();
        // uni.navigateBack();
        uni.switchTab({ url: '/pages/home/home' })
    };
    const toAgreement = () => {
miniprogram/pages/mine/mine.vue
@@ -4,16 +4,16 @@
        <view class="userInfo relative">
            <view class="info flex" @tap="goInfo">
                <image src="https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg" class="avatar"
                <image :src="info?.avatar" class="avatar"
                    mode="aspectFill">
                </image>
                <view class="info-de flex1 flex ml-19 j-between a-center">
                    <view class="nickName">
                        <view class="nickname">
                            卞琼梅
                            {{ info?.name || '-' }}
                        </view>
                        <view class="phone">
                            17475792147
                            {{ info?.phone || '-' }}
                        </view>
                    </view>
@@ -109,12 +109,24 @@
    import { ref, reactive } from "vue";
    import { htmlConfig, getUserInfo } from './service.js'
    const content = ref<string>("");
    const info = ref({ userType: 1, phone: '', code: '', profilePhoto: '' })
    const info = ref({  })
    onShow(() => {
        if (uni.getStorageSync('token')) {
        // getInfo()
            getInfo()
        } else {
            uni.showToast({
                icon: 'none',
                title: '请先登录后查看'
            })
            setTimeout(() => {
                uni.reLaunch({
                    url: '/pages/login/login'
                })
            }, 1500)
        }
    })
    const getInfo = () => {
        getUserInfo().then(res => {
miniprogram/pages/mineInfo/mineInfo.vue
@@ -2,7 +2,7 @@
    <view class="pl-27 pr-27 flex flex-column a-center">
        <view class="mt-37 w-192 h-192 relative" style="border-radius: 50%;" @tap="getAvatar">
            <image class="w-192 h-192"
                :src="avatar?avatar: 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png'"
                :src="avatar ? avatar : 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png'"
                mode="aspectFill" style="border-radius: 50%;">
            </image>
@@ -14,18 +14,19 @@
        </view>
        <view class="van-cell border1 w100 flex flex-column" @tap="getNickName">
            昵称
            <view class="flex a-center choice j-between" :class="nickName!='请选择'?'fs-bl':''">{{nickName}}
            <view class="flex a-center choice j-between" :class="nickName != '请选择' ? 'fs-bl' : ''">{{ nickName }}
                <image src="/static/image/mine/gary.png" class="w-23 h-23" mode="aspectFill"></image>
            </view>
        </view>
        <view class="van-cell border1  w100 flex flex-column" @tap="showSex = true">
            性别 <view class="flex a-center choice j-between" :class="gender!='请选择'?'fs-bl':''">{{gender}}
            性别 <view class="flex a-center choice j-between" :class="gender != '请选择' ? 'fs-bl' : ''">{{ gender }}
                <image src="/static/image/mine/gary.png" class="w-23 h-23" mode="aspectFill"></image>
            </view>
        </view>
        <view class="van-cell border1  w100 flex flex-column" @tap="showBir = true">
            生日 <view class="flex a-center choice flex1 j-between" :class="birthday!='请选择'?'fs-bl':''">{{birthday}}
            生日 <view class="flex a-center choice flex1 j-between" :class="birthday != '请选择' ? 'fs-bl' : ''">{{ birthday
            }}
                <image src="/static/image/mine/gary.png" class="w-23 h-23" mode="aspectFill"></image>
            </view>
        </view>
@@ -48,114 +49,151 @@
</template>
<script setup lang="ts">
    import { ref, reactive } from "vue";
    import { onLoad, onShow, onReachBottom } from "@dcloudio/uni-app"
    import checkSex from "../../components/checkSex.vue"
    import selectDateYear from "../../components/selectDateYear.vue"
import { ref, reactive } from "vue";
import { onLoad, onShow, onReachBottom } from "@dcloudio/uni-app"
import checkSex from "../../components/checkSex.vue"
import selectDateYear from "../../components/selectDateYear.vue"
import { getUserInfo } from '../mine/service.js'
    const nickName = ref('请选择')
    const gender = ref('请选择')
    const birthday = ref('请选择')
    const avatar = ref('')
    const phone = ref('')
const nickName = ref('请选择')
const gender = ref('请选择')
const birthday = ref('请选择')
const avatar = ref('')
const phone = ref('')
    // 性别选择弹窗显隐
    const showSex = ref(false)
    // 生日选择弹窗显隐
    const showBir = ref(false)
// 性别选择弹窗显隐
const showSex = ref(false)
// 生日选择弹窗显隐
const showBir = ref(false)
    // 性别选择回调
    const handleSexSubmit = (val : number[] | any) => {
        // 组件当前提交的是索引数组,例如 [0] / [1]
        const index = Array.isArray(val) ? val[0] : 0
        gender.value = index === 0 ? '男' : '女'
        showSex.value = false
// 性别选择回调
const handleSexSubmit = (val: number[] | any) => {
    // 组件当前提交的是索引数组,例如 [0] / [1]
    const index = Array.isArray(val) ? val[0] : 0
    gender.value = index === 0 ? '男' : '女'
    showSex.value = false
}
// 生日选择回调
const handleBirthdaySubmit = (dateValue: string) => {
    birthday.value = dateValue
    showBir.value = false
    // 这里可以添加更新用户信息的逻辑
    updateUserInfo()
}
const getNickName = () => {
    uni.getUserInfo({
        provider: 'weixin',
        success: (res) => {
            console.log(res)
            nickName.value = res.userInfo.nickName
            // updateUserInfo()
        }
    })
}
const updateUserInfo = () => {
    updateInfo({
        id: this.id,
        avatar: this.avatar,
        name: this.name,
        nickName: this.name,
        phone: this.phone,
        gender: this.sex == '男' ? 1 : 2,
        birthday: this.birthday == '请选择' ? null : this.birthday,
    })
}
onLoad(() => {
    if (uni.getStorageSync('token')) {
        getUserInfo().then(res => {
            if (res.code == 200) {
                avatar.value = res.data.avatar
                nickName.value = res.data.name || '请选择'
                phone.value = res.data.phone
                gender.value = res.data.gender == 1 ? '男' : res.data.gender == 2 ? '女' : '请选择'
                birthday.value = res.data.birthDate || '请选择'
            }
        })
    }
    // 生日选择回调
    const handleBirthdaySubmit = (dateValue : string) => {
        birthday.value = dateValue
        showBir.value = false
        // 这里可以添加更新用户信息的逻辑
        // updateUserInfo()
    }
})
</script>
<style scoped>
    page,
    html {
        background: #fff;
    }
<style>
page {
    background: #fff !important;
}
</style>
<style lang="scss" scoped>
    ::v-deep .popup-content {
        background-color: #fff;
    }
::v-deep .popup-content {
    background-color: #fff;
}
    .tip {
        height: 46rpx;
        background: rgba(0, 0, 0, 0.4);
.tip {
    height: 46rpx;
    background: #FFFFFF;
    font-family: PingFangSC, PingFang SC;
    font-weight: 500;
    font-size: 23rpx;
    color: #FFFFFF;
    display: flex;
    justify-content: center;
    align-items: center;
}
.van-cell {
    font-family: PingFangSC, PingFang SC;
    font-weight: 600;
    font-size: 28rpx;
    color: #333333;
    line-height: 60rpx;
    padding: 28.46rpx 0;
    .name {
        font-family: PingFangSC, PingFang SC;
        font-weight: 500;
        font-size: 23rpx;
        color: #FFFFFF;
        display: flex;
        justify-content: center;
        align-items: center;
        font-size: 27rpx;
        color: rgba(0, 0, 0, 0.85);
        line-height: 38rpx;
    }
}
    .van-cell {
        font-family: PingFangSC, PingFang SC;
        font-weight: 600;
        font-size: 28rpx;
        color: #333333;
        line-height: 60rpx;
        padding: 28.46rpx 0;
.border1 {
    border-bottom: 1rpx solid rgba(151, 151, 151, .2);
}
        .name {
            font-family: PingFangSC, PingFang SC;
            font-weight: 500;
            font-size: 27rpx;
            color: rgba(0, 0, 0, 0.85);
            line-height: 38rpx;
        }
    }
.choice {
    font-family: PingFangSC, PingFang SC;
    font-weight: 400;
    font-size: 28rpx;
    color: rgba(0, 0, 0, .4);
}
    .border1 {
        border-bottom: 1rpx solid rgba(151, 151, 151, .2);
    }
.fs-bl {
    font-family: PingFangSC, PingFang SC;
    font-weight: 600;
    font-size: 28rpx;
    color: #333333;
}
    .choice {
        font-family: PingFangSC, PingFang SC;
        font-weight: 400;
        font-size: 28rpx;
        color: rgba(0, 0, 0, .4);
    }
    .fs-bl {
        font-family: PingFangSC, PingFang SC;
        font-weight: 600;
        font-size: 28rpx;
        color: #333333;
    }
    .logout {
        position: fixed;
        bottom: 92.32rpx;
        width: 327rpx;
        height: 96rpx;
        background: #FFFFFF;
        box-shadow: 0rpx 4rpx 25rpx 0rpx rgba(255, 106, 11, 0.16);
        border-radius: 58rpx;
        border: 2rpx solid #06C584;
        font-family: PingFangSC, PingFang SC;
        font-weight: 500;
        font-size: 31rpx;
        color: #06C584;
        text-shadow: 0px 4px 25px rgba(255, 106, 11, 0.16);
        display: flex;
        justify-content: center;
        align-items: center;
    }
.logout {
    position: fixed;
    bottom: 92.32rpx;
    width: 327rpx;
    height: 96rpx;
    background: #FFFFFF;
    box-shadow: 0rpx 4rpx 25rpx 0rpx rgba(255, 106, 11, 0.16);
    border-radius: 58rpx;
    border: 2rpx solid #06C584;
    font-family: PingFangSC, PingFang SC;
    font-weight: 500;
    font-size: 31rpx;
    color: #06C584;
    text-shadow: 0px 4px 25px rgba(255, 106, 11, 0.16);
    display: flex;
    justify-content: center;
    align-items: center;
}
</style>
miniprogram/pages/tourist/tourist.vue
@@ -8,7 +8,7 @@
            <view v-for="(item, index) in list" :key="index" class="item" @click="selectTourist(item)">
                <view class="flex a-center">
                    <view class="name">{{ item.name }}</view>
                    <image src="../../static/image/mine/edit.png" class="w-23 h-23 ml-38" @click.stop="toAddTourist(item.id)"></image>
                    <image src="../../static/image/mine/modify.png" class="w-23 h-23 ml-38" @click.stop="toAddTourist(item.id)"></image>
                </view>
                <view class="flex a-center j-between info">
                    <view>身份证 {{ item.idCard }}</view>
miniprogram/static/image/login/unCheckbox.png
miniprogram/static/image/mine/arrowRight.png
miniprogram/static/image/mine/checked.png
miniprogram/static/image/mine/close.png
miniprogram/static/image/mine/modify.png
miniprogram/static/image/mine/ticket.png