Merge branch 'main' of http://120.76.84.145:10101/gitblit/r/H5/qingduTicketing
| | |
| | | export default { |
| | | dev: { |
| | | SERVER_URL: 'https://jiashikang.cn/manage', |
| | | IMAGE_URL: 'https://jiashikang.cn/images/', // 图片地址 |
| | | // SERVER_URL: 'https://jiashikang.cn/manage', |
| | | SERVER_URL: 'http://192.168.110.111:9918', |
| | | IMAGE_URL: 'http://192.168.110.111:11223/images/', // 图片地址 |
| | | }, |
| | | test: { |
| | | SERVER_URL: 'http://221.182.45.100:8686', |
| | |
| | | "component": "./strategyManagement/index" |
| | | }, |
| | | { |
| | | "name": "新增公告", |
| | | "name": "新增攻略", |
| | | "path": "/strategyManagement/addAndEdit", |
| | | "component": "./strategyManagement/addAndEdit", |
| | | "hideInMenu": true |
| | |
| | | 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) => ({ |
| | | 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: IMAGE_URL + url, |
| | | })); |
| | | url: imageUrl, |
| | | response: url, // 保存原始值 |
| | | }; |
| | | }); |
| | | setCarouselImageList(fileList); |
| | | form.setFieldValue('carouselImages', imageArray.join(',')); |
| | | // 将 detailImages 设置为逗号分隔的字符串 |
| | | const detailImagesStr = imageArray.join(','); |
| | | form.setFieldValue('detailImages', detailImagesStr); |
| | | } |
| | | |
| | | // 设置富文本内容 |
| | |
| | | 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 }); |
| | | }; |
| | | |
| | |
| | | // 如果是已存在的图片,从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(',') }); |
| | | }; |
| | | |
| | | // 处理轮播图删除 |
| | |
| | | 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; |
| | | }; |
| | | |
| | |
| | | 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, |
| | | }; |
| | | |
| | |
| | | {/* 公告标题 */} |
| | | <ProFormText |
| | | name="title" |
| | | label="*公告标题" |
| | | label="公告标题" |
| | | placeholder="请输入" |
| | | wrapperCol={{ span: 12 }} |
| | | rules={[{ required: true, message: '请输入公告标题' }]} |
| | |
| | | </Form.Item> |
| | | |
| | | {/* 详情轮播图 */} |
| | | <Form.Item name="carouselImages" label="详情轮播图"> |
| | | <Form.Item name="detailImages" label="详情轮播图"> |
| | | <Upload |
| | | name="carouselImages" |
| | | name="detailImages" |
| | | listType="picture-card" |
| | | fileList={carouselImageList} |
| | | beforeUpload={beforeUpload} |
| | |
| | | fieldProps={{ |
| | | style: { width: '120px' }, |
| | | }} |
| | | initialValue={45} |
| | | /> |
| | | <div style={{ fontSize: '12px', color: '#999', marginTop: '4px', marginLeft: '8px' }}> |
| | | 数值越大越靠前 |
| | |
| | | </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> |
| | |
| | | {/* 公告内容 */} |
| | | <Form.Item |
| | | name="content" |
| | | label="*公告内容" |
| | | label="公告内容" |
| | | wrapperCol={{ span: 24 }} |
| | | rules={[{ required: true, message: '请输入公告内容' }]} |
| | | // rules={[{ required: true, message: '请输入公告内容' }]} |
| | | > |
| | | <BraftEditorCom |
| | | data={announcementContent.content || ''} |
| | |
| | | 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('删除成功'); |
| | | const status = await sendRequest(deleteAnnouncement, id); |
| | | if (status) { |
| | | actionRef.current?.reload(); |
| | | } else { |
| | | message.error(res.msg || '删除失败'); |
| | | } |
| | | } catch (error) { |
| | | message.error('删除失败'); |
| | | } |
| | | }; |
| | | |
| | |
| | | }, |
| | | }, |
| | | { |
| | | title: '发布时间', |
| | | dataIndex: 'publishTime', |
| | | valueType: 'date', |
| | | width: 150, |
| | | title: '创建时间', |
| | | dataIndex: 'createTime', |
| | | valueType: 'dateTime', |
| | | width: 180, |
| | | align: 'center', |
| | | hideInTable: false, |
| | | fieldProps: { |
| | |
| | | }, |
| | | }, |
| | | { |
| | | 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, |
| | | }, |
| | |
| | | <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> |
| | | </Space> |
| | | ), |
| | | }, |
| | |
| | | 新增公告 |
| | | </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) => ({ |
| | | const result = await buildProTableDataSource(getAnnouncementList, requestParams); |
| | | // 添加序号 |
| | | result.data = result.data.map((item, index) => ({ |
| | | ...item, |
| | | index: (current - 1) * pageSize + index + 1, |
| | | })), |
| | | success: res.code === 200, |
| | | total: res.data?.total || 0, |
| | | }; |
| | | index: ((current || 1) - 1) * (pageSize || 10) + index + 1, |
| | | })); |
| | | return result; |
| | | }} |
| | | columns={columns} |
| | | scroll={{ x: 1200 }} |
| | |
| | | |
| | | // 获取公告列表(分页) |
| | | export async function getAnnouncementList(params) { |
| | | return request('/announcement/page', { |
| | | return request('/t-notice/pageList', { |
| | | method: 'POST', |
| | | data: params, |
| | | }); |
| | |
| | | |
| | | // 删除公告 |
| | | 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, |
| | | }); |
| | |
| | | |
| | | // 编辑公告 |
| | | export async function editAnnouncement(params) { |
| | | return request('/announcement', { |
| | | method: 'PUT', |
| | | return request('/t-notice/update', { |
| | | method: 'POST', |
| | | data: params, |
| | | }); |
| | | } |
| | |
| | | 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' |
| | |
| | | |
| | | // 删除订单 |
| | | 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 || '删除失败'); |
| | | } |
| | | }; |
| | | |
| | |
| | | </Button> |
| | | </Access> |
| | | <Access accessible={access.physicalGoodsOrder_del || false}> |
| | | <Popconfirm title="确认删除?" onConfirm={() => handleDelete(record.id)}> |
| | | <Button type="link" danger> |
| | | <Button |
| | | type="link" |
| | | danger |
| | | onClick={() => { |
| | | showDelConfirm(async () => { |
| | | await handleDelete(record.id); |
| | | }, '删除后不可恢复,请谨慎操作!', '确认', '取消', '确认删除?'); |
| | | }} |
| | | > |
| | | 删除 |
| | | </Button> |
| | | </Popconfirm> |
| | | </Access> |
| | | </Space> |
| | | ), |
| | |
| | | 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, |
| | |
| | | |
| | | // 获取实物商品订单列表 |
| | | export async function getPhysicalGoodsOrderList(params) { |
| | | return request('/t-physical-goods-order/pageList', { |
| | | return request('/t-ticket-order/pageList', { |
| | | method: 'POST', |
| | | data: params, |
| | | }); |
| | |
| | | |
| | | // 获取实物商品订单详情 |
| | | export async function getPhysicalGoodsOrderDetail(id) { |
| | | return request(`/t-physical-goods-order/detail/${id}`, { |
| | | return request(`/t-ticket-order/detail/${id}`, { |
| | | method: 'GET', |
| | | }); |
| | | } |
| | |
| | | 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'; |
| | |
| | | </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> |
| | | </Access> |
| | | </> |
| | | ), |
| | |
| | | |
| | | // 删除退款申请 |
| | | const handleDelete = async (id) => { |
| | | try { |
| | | const res = await deleteRefundApplication(id); |
| | | if (res.code === 200) { |
| | | message.success('删除成功'); |
| | | const status = await sendRequest(deleteRefundApplication, id); |
| | | if (status) { |
| | | actionRef.current?.reload(); |
| | | } else { |
| | | message.error(res.msg || '删除失败'); |
| | | } |
| | | } catch (error) { |
| | | message.error('删除失败'); |
| | | } |
| | | }; |
| | | |
| | |
| | | }} |
| | | 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 }} |
| | |
| | | |
| | | // 获取退款申请列表 |
| | | export async function pageRefundList(params) { |
| | | return request('/t-refund-application/pageRefundList', { |
| | | return request('/t-ticket-order/refundPageList', { |
| | | method: 'POST', |
| | | data: params, |
| | | }); |
| | |
| | | |
| | | // 审核退款申请 |
| | | export async function refundAudit(params) { |
| | | return request('/t-refund-application/refundAudit', { |
| | | return request('/t-ticket-order/refundAudit', { |
| | | method: 'POST', |
| | | data: params, |
| | | }); |
| | |
| | | const [form] = Form.useForm(); |
| | | const [searchParams] = useSearchParams(); |
| | | const [loading, setLoading] = useState(false); |
| | | const [coverImageUrl, setCoverImageUrl] = useState(''); |
| | | const [coverImageList, setCoverImageList] = useState([]); |
| | | const [detailImageList, setDetailImageList] = useState([]); |
| | | const [detailVideoList, setDetailVideoList] = useState([]); |
| | | const [detailTabActiveKey, setDetailTabActiveKey] = useState('image'); |
| | |
| | | form.setFieldsValue({ |
| | | title: data.title, |
| | | coverImage: data.coverImage, |
| | | sortOrder: data.sortOrder || 45, |
| | | sortOrder: data.sort || 45, |
| | | detailImages: data.detailImages, |
| | | detailVideos: data.detailVideos, |
| | | }); |
| | | |
| | | // 设置封面图 |
| | | if (data.coverImage) { |
| | | setCoverImageUrl(IMAGE_URL + data.coverImage); |
| | | // 判断是否是完整URL |
| | | const isFullUrl = data.coverImage.startsWith('http://') || data.coverImage.startsWith('https://'); |
| | | const imageUrl = isFullUrl |
| | | ? data.coverImage |
| | | : IMAGE_URL + data.coverImage.replace(/^\/+/, ''); // 去除开头的斜杠 |
| | | |
| | | setCoverImageList([ |
| | | { |
| | | uid: '-1', |
| | | name: 'coverImage.jpg', |
| | | status: 'done', |
| | | url: imageUrl, |
| | | response: data.coverImage, // 保存原始值(相对路径或完整URL) |
| | | }, |
| | | ]); |
| | | } else { |
| | | setCoverImageList([]); |
| | | } |
| | | |
| | | // 设置详情图 |
| | | // 根据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 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: IMAGE_URL + url, |
| | | 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) => ({ |
| | | 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: IMAGE_URL + url, |
| | | url: videoUrl, |
| | | response: url, |
| | | })); |
| | | }; |
| | | }); |
| | | setDetailVideoList(fileList); |
| | | } |
| | | } |
| | | |
| | | // 设置富文本内容 |
| | |
| | | let params = strategyContent; |
| | | params.content = html; |
| | | setStrategyContent(params); |
| | | form.setFieldsValue({ content: params }); |
| | | // form.setFieldsValue({ content: params }); |
| | | }; |
| | | |
| | | // 处理封面图上传成功 |
| | | const handleCoverImageSuccess = (response) => { |
| | | setCoverImageUrl(IMAGE_URL + response); |
| | | form.setFieldsValue({ coverImage: response }); |
| | | // 处理封面图上传变化 |
| | | const handleCoverImageChange = ({ fileList }) => { |
| | | setCoverImageList(fileList); |
| | | // 提取已上传成功的图片URL |
| | | const imagePath = fileList |
| | | .filter((file) => file.status === 'done') |
| | | .map((file) => { |
| | | if (file.response) { |
| | | return file.response; |
| | | } |
| | | if (file.url && file.url.startsWith(IMAGE_URL)) { |
| | | return file.url.replace(IMAGE_URL, ''); |
| | | } |
| | | return file.url; |
| | | }) |
| | | .filter(Boolean)[0]; |
| | | form.setFieldsValue({ coverImage: imagePath || '' }); |
| | | }; |
| | | |
| | | // 处理封面图删除 |
| | | const handleCoverImageRemove = (file) => { |
| | | setCoverImageList([]); |
| | | form.setFieldsValue({ coverImage: '' }); |
| | | return true; |
| | | }; |
| | | |
| | | // 自定义封面图上传请求 |
| | | const customCoverImageRequest = (options) => { |
| | | const { file, onSuccess, onError } = options; |
| | | uploadFile(file) |
| | | .then((ret) => { |
| | | if (ret && ret.data) { |
| | | onSuccess({ |
| | | uid: file.uid, |
| | | name: file.name, |
| | | status: 'done', |
| | | url: IMAGE_URL + ret.data, |
| | | response: ret.data, |
| | | }); |
| | | } else { |
| | | onError(); |
| | | } |
| | | }) |
| | | .catch(() => { |
| | | onError(); |
| | | }); |
| | | }; |
| | | |
| | | // 处理详情图片上传成功 |
| | |
| | | try { |
| | | const values = await form.validateFields(); |
| | | |
| | | console.log('wewqeqwe',detailImageList); |
| | | |
| | | |
| | | |
| | | // 验证封面图 |
| | | if (!coverImageUrl) { |
| | | const coverImage = values.coverImage; |
| | | if (!coverImage) { |
| | | message.error('请上传封面图'); |
| | | return; |
| | | } |
| | |
| | | return; |
| | | } |
| | | |
| | | // 根据当前选中的tab确定type |
| | | const type = detailTabActiveKey === 'image' ? 1 : 2; |
| | | |
| | | // 从 coverImageList 中取 response(相对路径字符串) |
| | | // 如果 response 是完整URL,提取相对路径 |
| | | const getRelativePath = (path) => { |
| | | if (!path) return ''; |
| | | if (path.startsWith('http://') || path.startsWith('https://')) { |
| | | // 如果是完整URL,尝试提取相对路径 |
| | | if (path.includes(IMAGE_URL)) { |
| | | return path.replace(IMAGE_URL, '').replace(/^\/+/, ''); |
| | | } |
| | | // 如果不在 IMAGE_URL 中,返回原值(可能是外部URL) |
| | | return path; |
| | | } |
| | | // 已经是相对路径,去除开头的斜杠 |
| | | return path.replace(/^\/+/, ''); |
| | | }; |
| | | |
| | | const coverImageResponse = coverImageList |
| | | .filter((file) => file.status === 'done') |
| | | .map((file) => getRelativePath(file.response)) |
| | | .filter(Boolean)[0] || ''; |
| | | |
| | | // detailImages 需要传字符串(逗号分隔) |
| | | const detailImagesStr = type === 1 |
| | | ? detailImageList |
| | | .filter((item) => item.status === 'done') |
| | | .map((item) => getRelativePath(item.response)) |
| | | .filter(Boolean) |
| | | .join(',') |
| | | : detailVideoList |
| | | .filter((item) => item.status === 'done') |
| | | .map((item) => getRelativePath(item.response)) |
| | | .filter(Boolean) |
| | | .join(','); |
| | | |
| | | // 准备提交数据 |
| | | const submitData = { |
| | | title: values.title, |
| | | coverImage: values.coverImage, |
| | | sortOrder: values.sortOrder || 45, |
| | | detailImages: values.detailImages || '', |
| | | detailVideos: values.detailVideos || '', |
| | | coverImage: coverImageResponse, // 只取 response(相对路径字符串) |
| | | sort: values.sortOrder || 45, |
| | | detailImages: detailImagesStr, // 传字符串(逗号分隔) |
| | | type: type, |
| | | content: strategyContent.content, |
| | | }; |
| | | |
| | |
| | | {/* 攻略标题 */} |
| | | <ProFormText |
| | | name="title" |
| | | label="*攻略标题" |
| | | label="攻略标题" |
| | | placeholder="请输入" |
| | | wrapperCol={{ span: 12 }} |
| | | rules={[{ required: true, message: '请输入攻略标题' }]} |
| | |
| | | <Upload |
| | | name="coverImage" |
| | | listType="picture-card" |
| | | showUploadList={false} |
| | | fileList={coverImageList} |
| | | beforeUpload={beforeUploadImage} |
| | | disabled={loading || isReadOnly} |
| | | customRequest={customRequest} |
| | | customRequest={customCoverImageRequest} |
| | | accept="image/*" |
| | | onSuccess={handleCoverImageSuccess} |
| | | onRemove={() => { |
| | | setCoverImageUrl(''); |
| | | form.setFieldsValue({ coverImage: '' }); |
| | | }} |
| | | onChange={handleCoverImageChange} |
| | | onRemove={handleCoverImageRemove} |
| | | > |
| | | {coverImageUrl ? ( |
| | | <img |
| | | src={coverImageUrl} |
| | | alt="封面图" |
| | | style={{ width: '100%', height: '100%', objectFit: 'cover' }} |
| | | /> |
| | | ) : ( |
| | | uploadButton |
| | | )} |
| | | {coverImageList.length >= 1 ? null : uploadButton} |
| | | </Upload> |
| | | </Form.Item> |
| | | |
| | |
| | | <ProFormDigit |
| | | name="sortOrder" |
| | | label="排序:" |
| | | placeholder="45" |
| | | placeholder="请输入" |
| | | min={0} |
| | | disabled={isReadOnly} |
| | | fieldProps={{ |
| | | style: { width: '120px' }, |
| | | }} |
| | | initialValue={45} |
| | | /> |
| | | <div style={{ fontSize: '12px', color: '#999', marginTop: '4px', marginLeft: '8px' }}> |
| | | 数值越大越靠前 |
| | |
| | | {/* 攻略内容 */} |
| | | <Form.Item |
| | | name="content" |
| | | label="*攻略内容" |
| | | label="攻略内容" |
| | | wrapperCol={{ span: 24 }} |
| | | rules={[{ required: true, message: '请输入攻略内容' }]} |
| | | // rules={[{ required: true, message: '请输入攻略内容' }]} |
| | | > |
| | | <BraftEditorCom |
| | | data={strategyContent.content || ''} |
| | |
| | | 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 = () => { |
| | |
| | | |
| | | // 删除攻略 |
| | | const handleDelete = async (id) => { |
| | | try { |
| | | const res = await deleteStrategy(id); |
| | | if (res.code === 200) { |
| | | message.success('删除成功'); |
| | | const status = await sendRequest(deleteStrategy, id); |
| | | if (status) { |
| | | actionRef.current?.reload(); |
| | | } else { |
| | | message.error(res.msg || '删除失败'); |
| | | } |
| | | } catch (error) { |
| | | message.error('删除失败'); |
| | | } |
| | | }; |
| | | |
| | |
| | | }, |
| | | }, |
| | | { |
| | | title: '发布时间', |
| | | dataIndex: 'publishTime', |
| | | valueType: 'date', |
| | | width: 150, |
| | | title: '创建时间', |
| | | dataIndex: 'createTime', |
| | | valueType: 'dateTime', |
| | | width: 180, |
| | | align: 'center', |
| | | hideInTable: false, |
| | | fieldProps: { |
| | |
| | | }, |
| | | }, |
| | | { |
| | | title: '浏览人数', |
| | | dataIndex: 'viewCount', |
| | | title: '创建人', |
| | | dataIndex: 'createBy', |
| | | hideInSearch: true, |
| | | width: 120, |
| | | align: 'center', |
| | | ellipsis: true, |
| | | }, |
| | | { |
| | | title: '浏览量', |
| | | dataIndex: 'lookNum', |
| | | hideInSearch: true, |
| | | width: 120, |
| | | align: 'center', |
| | | render: (text) => text || 0, |
| | | }, |
| | | { |
| | | title: '排序', |
| | | dataIndex: 'sort', |
| | | hideInSearch: true, |
| | | width: 100, |
| | | align: 'center', |
| | | render: (text) => text || 0, |
| | | }, |
| | | { |
| | | title: '类型', |
| | | dataIndex: 'type', |
| | | hideInSearch: true, |
| | | width: 100, |
| | | align: 'center', |
| | | render: (text) => { |
| | | if (text === 1) return '图片'; |
| | | if (text === 2) return '视频'; |
| | | return '-'; |
| | | }, |
| | | }, |
| | | { |
| | | title: '操作', |
| | |
| | | <Button 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> |
| | | </Space> |
| | | ), |
| | | }, |
| | |
| | | 新增攻略 |
| | | </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) => ({ |
| | | const result = await buildProTableDataSource(getStrategyList, requestParams); |
| | | // 添加序号 |
| | | result.data = result.data.map((item, index) => ({ |
| | | ...item, |
| | | index: (current - 1) * pageSize + index + 1, |
| | | })), |
| | | success: res.code === 200, |
| | | total: res.data?.total || 0, |
| | | }; |
| | | index: ((current || 1) - 1) * (pageSize || 10) + index + 1, |
| | | })); |
| | | return result; |
| | | }} |
| | | columns={columns} |
| | | scroll={{ x: 1200 }} |
| | |
| | | |
| | | // 获取攻略列表(分页) |
| | | export async function getStrategyList(params) { |
| | | return request('/strategy/page', { |
| | | return request('/t-guide/pageList', { |
| | | method: 'POST', |
| | | data: params, |
| | | }); |
| | |
| | | |
| | | // 删除攻略 |
| | | export async function deleteStrategy(id) { |
| | | return request(`/strategy/${id}`, { |
| | | return request(`/t-guide/delete/${id}`, { |
| | | method: 'DELETE', |
| | | }); |
| | | } |
| | | |
| | | // 获取攻略详情 |
| | | export async function getStrategyDetail(id) { |
| | | return request(`/strategy/${id}`, { |
| | | return request(`/t-guide/detail/${id}`, { |
| | | method: 'GET', |
| | | }); |
| | | } |
| | | |
| | | // 新增攻略 |
| | | export async function addStrategy(params) { |
| | | return request('/strategy', { |
| | | return request('/t-guide/add', { |
| | | method: 'POST', |
| | | data: params, |
| | | }); |
| | |
| | | |
| | | // 编辑攻略 |
| | | export async function editStrategy(params) { |
| | | return request('/strategy', { |
| | | method: 'PUT', |
| | | return request('/t-guide/update', { |
| | | method: 'post', |
| | | data: params, |
| | | }); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | |
| | | 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/' |
| | | }; |
| | |
| | | { |
| | | "sassImplementationName" : "node-sass", |
| | | "name" : "青城后山", |
| | | "appid" : "__UNI__E5BD0E6", |
| | | "appid" : "__UNI__B98B5B1", |
| | | "description" : "", |
| | | "versionName" : "1.0.0", |
| | | "versionCode" : "100", |
| | |
| | | "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": [{ |
| New file |
| | |
| | | <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> |
| New file |
| | |
| | | <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> |
| New file |
| | |
| | | <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> |
| New file |
| | |
| | | <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> |
| New file |
| | |
| | | <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> |
| New file |
| | |
| | | <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> |
| | |
| | | |
| | | 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); |
| | |
| | | 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(() => { |
| | |
| | | loginType.value = true; |
| | | return; |
| | | } |
| | | uni.navigateBack(); |
| | | // uni.navigateBack(); |
| | | uni.switchTab({ url: '/pages/home/home' }) |
| | | }; |
| | | |
| | | const toAgreement = () => { |
| | |
| | | |
| | | <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> |
| | | |
| | |
| | | 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 => { |
| | |
| | | </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> |
| | |
| | | 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('请选择') |
| | |
| | | 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 || '请选择' |
| | | } |
| | | }) |
| | | } |
| | | }) |
| | | </script> |
| | | |
| | | <style scoped> |
| | | page, |
| | | html { |
| | | background: #fff; |
| | | <style> |
| | | page { |
| | | background: #fff !important; |
| | | } |
| | | </style> |
| | | |
| | |
| | | |
| | | .tip { |
| | | height: 46rpx; |
| | | background: rgba(0, 0, 0, 0.4); |
| | | background: #FFFFFF; |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-weight: 500; |
| | | font-size: 23rpx; |
| | |
| | | <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> |