feat(user): 新增收货地址管理及售后申请页面
- 新增地址类型定义,增强前端地址数据结构 - 新增地址编辑页面,支持地址智能识别和定位选点功能 - 地址编辑支持省市区选择及默认地址设置 - 新增地址列表页面,支持地址展示、删除、编辑和选择功能 - 实现售后申请页面,支持选择售后类型和退款原因 - 售后申请支持商品选择、退款金额计算和凭证上传 - 新增售后详情页面,支持售后状态展示及申请取消 - 优化页面加载和用户交互体验,增加错误提示和权限处理
This commit is contained in:
153
src_bak/pages/invoice/apply/index.tsx
Normal file
153
src_bak/pages/invoice/apply/index.tsx
Normal file
@@ -0,0 +1,153 @@
|
||||
import { View, Text, Input, Textarea } from '@tarojs/components';
|
||||
import { useState } from 'react';
|
||||
import Taro from '@tarojs/taro';
|
||||
import NavBar from '@/components/NavBar';
|
||||
|
||||
export default function InvoiceApplyPage() {
|
||||
const [invoiceType, setInvoiceType] = useState<'personal' | 'company'>('personal');
|
||||
const [formData, setFormData] = useState({
|
||||
title: '',
|
||||
taxNumber: '',
|
||||
content: '商品明细',
|
||||
amount: '',
|
||||
email: '',
|
||||
remark: ''
|
||||
});
|
||||
|
||||
const handleSubmit = () => {
|
||||
// TODO: 接入发票申请 API
|
||||
Taro.showToast({ title: '发票申请功能开发中', icon: 'none' })
|
||||
};
|
||||
|
||||
return (
|
||||
<View className="bg-gray-100 flex flex-col" style={{ minHeight: '100vh' }}>
|
||||
<NavBar title="申请发票" />
|
||||
|
||||
<View className="flex-1 p-4">
|
||||
{/* 发票类型 */}
|
||||
<View className="bg-white rounded-lg p-4 mb-4">
|
||||
<Text className="text-base font-medium mb-3 block">发票类型</Text>
|
||||
<View className="flex" style={{ gap: '16px' }}>
|
||||
<View
|
||||
className={`flex-1 p-3 rounded-lg border-2 text-center ${
|
||||
invoiceType === 'personal'
|
||||
? 'border-red-500 bg-red-50'
|
||||
: 'border-gray-300'
|
||||
}`}
|
||||
onClick={() => setInvoiceType('personal')}
|
||||
>
|
||||
<Text className={invoiceType === 'personal' ? 'text-red-500' : 'text-gray-600'}>
|
||||
个人
|
||||
</Text>
|
||||
</View>
|
||||
<View
|
||||
className={`flex-1 p-3 rounded-lg border-2 text-center ${
|
||||
invoiceType === 'company'
|
||||
? 'border-red-500 bg-red-50'
|
||||
: 'border-gray-300'
|
||||
}`}
|
||||
onClick={() => setInvoiceType('company')}
|
||||
>
|
||||
<Text className={invoiceType === 'company' ? 'text-red-500' : 'text-gray-600'}>
|
||||
企业
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 发票信息 */}
|
||||
<View className="bg-white rounded-lg p-4 mb-4">
|
||||
<Text className="text-base font-medium mb-3 block">发票信息</Text>
|
||||
|
||||
<View className="mb-4">
|
||||
<Text className="text-sm text-gray-600 mb-2 block">发票抬头</Text>
|
||||
<Input
|
||||
className="w-full p-3 bg-gray-100 rounded-lg text-sm"
|
||||
placeholder="请输入发票抬头"
|
||||
value={formData.title}
|
||||
onInput={(e: any) => setFormData(prev => ({ ...prev, title: e.detail.value }))}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{invoiceType === 'company' && (
|
||||
<View className="mb-4">
|
||||
<Text className="text-sm text-gray-600 mb-2 block">税号</Text>
|
||||
<Input
|
||||
className="w-full p-3 bg-gray-100 rounded-lg text-sm"
|
||||
placeholder="请输入纳税人识别号"
|
||||
value={formData.taxNumber}
|
||||
onInput={(e: any) => setFormData(prev => ({ ...prev, taxNumber: e.detail.value }))}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
|
||||
<View className="mb-4">
|
||||
<Text className="text-sm text-gray-600 mb-2 block">发票内容</Text>
|
||||
<View className="flex" style={{ gap: '16px' }}>
|
||||
<View
|
||||
className={`px-4 py-2 rounded-lg ${
|
||||
formData.content === '商品明细' ? 'bg-red-500 text-white' : 'bg-gray-100 text-gray-600'
|
||||
}`}
|
||||
onClick={() => setFormData(prev => ({ ...prev, content: '商品明细' }))}
|
||||
>
|
||||
<Text>商品明细</Text>
|
||||
</View>
|
||||
<View
|
||||
className={`px-4 py-2 rounded-lg ${
|
||||
formData.content === '商品类别' ? 'bg-red-500 text-white' : 'bg-gray-100 text-gray-600'
|
||||
}`}
|
||||
onClick={() => setFormData(prev => ({ ...prev, content: '商品类别' }))}
|
||||
>
|
||||
<Text>商品类别</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View className="mb-4">
|
||||
<Text className="text-sm text-gray-600 mb-2 block">发票金额</Text>
|
||||
<Input
|
||||
className="w-full p-3 bg-gray-100 rounded-lg text-sm"
|
||||
placeholder="请输入发票金额"
|
||||
type="digit"
|
||||
value={formData.amount}
|
||||
onInput={(e: any) => setFormData(prev => ({ ...prev, amount: e.detail.value }))}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 接收方式 */}
|
||||
<View className="bg-white rounded-lg p-4 mb-4">
|
||||
<Text className="text-base font-medium mb-3 block">接收方式</Text>
|
||||
<View className="mb-4">
|
||||
<Text className="text-sm text-gray-600 mb-2 block">电子邮箱</Text>
|
||||
<Input
|
||||
className="w-full p-3 bg-gray-100 rounded-lg text-sm"
|
||||
placeholder="请输入接收邮箱"
|
||||
value={formData.email}
|
||||
onInput={(e: any) => setFormData(prev => ({ ...prev, email: e.detail.value }))}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<View className="mb-4">
|
||||
<Text className="text-sm text-gray-600 mb-2 block">备注</Text>
|
||||
<Textarea
|
||||
className="w-full p-3 bg-gray-100 rounded-lg text-sm"
|
||||
placeholder="选填,可填写备注信息"
|
||||
value={formData.remark}
|
||||
onInput={(e: any) => setFormData(prev => ({ ...prev, remark: e.detail.value }))}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View className="p-4 bg-white border-t border-gray-200" style={{ paddingBottom: '20px' }}>
|
||||
<View
|
||||
className="bg-red-500 text-white rounded-full w-full h-12 flex items-center justify-center"
|
||||
onClick={handleSubmit}
|
||||
>
|
||||
<Text className="text-white font-medium">提交申请</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
224
src_bak/pages/invoice/records/index.tsx
Normal file
224
src_bak/pages/invoice/records/index.tsx
Normal file
@@ -0,0 +1,224 @@
|
||||
import { View, Text, ScrollView } from '@tarojs/components';
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { useDidShow } from '@tarojs/taro';
|
||||
import Taro from '@tarojs/taro';
|
||||
import NavBar from '@/components/NavBar';
|
||||
import LoadMore from '@/components/common/LoadMore';
|
||||
import EmptyState from '@/components/common/EmptyState';
|
||||
import { pageShopInvoiceRecord } from '@/api/shop/shopInvoiceTitle';
|
||||
import type { ShopInvoiceRecord, ShopInvoiceRecordParam } from '@/api/shop/shopInvoiceTitle/model';
|
||||
import type { PageResult } from '@/api';
|
||||
|
||||
// 发票状态映射
|
||||
const statusMap = {
|
||||
0: { text: '待处理', color: 'text-orange-500', bgColor: 'bg-orange-100', textColor: 'text-orange-600' },
|
||||
1: { text: '开票中', color: 'text-blue-500', bgColor: 'bg-blue-100', textColor: 'text-blue-600' },
|
||||
2: { text: '已完成', color: 'text-green-500', bgColor: 'bg-green-100', textColor: 'text-green-600' },
|
||||
3: { text: '失败', color: 'text-red-500', bgColor: 'bg-red-100', textColor: 'text-red-600' },
|
||||
};
|
||||
|
||||
// 发票类型映射
|
||||
const invoiceTypeMap = {
|
||||
normal: { label: '普通发票', bgColor: 'bg-blue-100', textColor: 'text-blue-600' },
|
||||
vat: { label: '增值税发票', bgColor: 'bg-orange-100', textColor: 'text-orange-600' },
|
||||
};
|
||||
|
||||
export default function InvoiceRecordsPage() {
|
||||
const [records, setRecords] = useState<ShopInvoiceRecord[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [loadingMore, setLoadingMore] = useState(false);
|
||||
const [hasMore, setHasMore] = useState(true);
|
||||
const [page, setPage] = useState(1);
|
||||
const [activeTab, setActiveTab] = useState<'all' | 'pending' | 'completed'>('all');
|
||||
|
||||
// 过滤后的记录
|
||||
const filteredRecords = records.filter(record => {
|
||||
if (activeTab === 'all') return true;
|
||||
if (activeTab === 'pending') return record.status === 0 || record.status === 1;
|
||||
if (activeTab === 'completed') return record.status === 2;
|
||||
return true;
|
||||
});
|
||||
|
||||
// 加载数据
|
||||
const loadData = useCallback(async (pageNum: number = 1, isLoadMore = false) => {
|
||||
if (isLoadMore) {
|
||||
setLoadingMore(true);
|
||||
} else {
|
||||
setLoading(true);
|
||||
}
|
||||
|
||||
try {
|
||||
const params: ShopInvoiceRecordParam = {
|
||||
page: pageNum,
|
||||
limit: 10,
|
||||
order: 'desc',
|
||||
sort: 'createTime',
|
||||
};
|
||||
|
||||
const result: PageResult<ShopInvoiceRecord> = await pageShopInvoiceRecord(params);
|
||||
|
||||
if (result && result.list) {
|
||||
if (isLoadMore) {
|
||||
setRecords(prev => [...prev, ...result.list]);
|
||||
} else {
|
||||
setRecords(result.list);
|
||||
}
|
||||
setHasMore(result.list.length >= 10);
|
||||
setPage(pageNum);
|
||||
}
|
||||
} catch (e: any) {
|
||||
console.error('获取发票记录失败:', e);
|
||||
Taro.showToast({ title: e.message || '获取数据失败', icon: 'none' });
|
||||
} finally {
|
||||
setLoading(false);
|
||||
setLoadingMore(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
// 下拉刷新
|
||||
const onPullDownRefresh = useCallback(() => {
|
||||
loadData(1).then(() => {
|
||||
Taro.stopPullDownRefresh();
|
||||
});
|
||||
}, [loadData]);
|
||||
|
||||
// 上拉加载更多
|
||||
const onReachBottom = useCallback(() => {
|
||||
if (!loadingMore && hasMore) {
|
||||
loadData(page + 1, true);
|
||||
}
|
||||
}, [loadingMore, hasMore, page, loadData]);
|
||||
|
||||
useEffect(() => {
|
||||
loadData(1);
|
||||
}, []);
|
||||
|
||||
// 格式化金额
|
||||
const formatMoney = (money: number | undefined) => {
|
||||
return `¥${(money || 0).toFixed(2)}`;
|
||||
};
|
||||
|
||||
// 格式化时间
|
||||
const formatDate = (dateStr: string | undefined) => {
|
||||
if (!dateStr) return '';
|
||||
const date = new Date(dateStr);
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
const hour = String(date.getHours()).padStart(2, '0');
|
||||
const minute = String(date.getMinutes()).padStart(2, '0');
|
||||
return `${date.getFullYear()}-${month}-${day} ${hour}:${minute}`;
|
||||
};
|
||||
|
||||
// 获取状态信息
|
||||
const getStatusInfo = (status: number | undefined) => {
|
||||
return statusMap[status as keyof typeof statusMap] || statusMap[0];
|
||||
};
|
||||
|
||||
// 获取类型信息
|
||||
const getTypeInfo = (invoiceType: string | undefined) => {
|
||||
return invoiceTypeMap[invoiceType as keyof typeof invoiceTypeMap] || invoiceTypeMap.normal;
|
||||
};
|
||||
|
||||
// 查看发票
|
||||
const handleViewInvoice = (record: ShopInvoiceRecord) => {
|
||||
if (record.invoiceUrl) {
|
||||
Taro.previewImage({ urls: [record.invoiceUrl] });
|
||||
} else {
|
||||
Taro.showToast({ title: '暂无发票', icon: 'none' });
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<View className="min-h-screen bg-gray-100">
|
||||
<NavBar title="发票记录" />
|
||||
|
||||
{/* 标签切换 */}
|
||||
<View className="bg-white flex">
|
||||
{[
|
||||
{ key: 'all', label: '全部' },
|
||||
{ key: 'pending', label: '待处理' },
|
||||
{ key: 'completed', label: '已完成' }
|
||||
].map(tab => (
|
||||
<View
|
||||
key={tab.key}
|
||||
className={`flex-1 py-3 text-center relative ${
|
||||
activeTab === tab.key ? 'text-red-500 font-medium' : 'text-gray-500'
|
||||
}`}
|
||||
onClick={() => setActiveTab(tab.key as any)}
|
||||
>
|
||||
<Text>{tab.label}</Text>
|
||||
{activeTab === tab.key && (
|
||||
<View className="absolute bottom-0 w-8 bg-red-500 rounded-t" style={{ left: '50%', transform: 'translateX(-50%)', height: '4px' }} />
|
||||
)}
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
|
||||
{/* 记录列表 */}
|
||||
{loading ? (
|
||||
<LoadMore loading />
|
||||
) : filteredRecords.length === 0 ? (
|
||||
<EmptyState message="暂无发票记录" />
|
||||
) : (
|
||||
<ScrollView
|
||||
scrollY
|
||||
className="p-4"
|
||||
onScrollToLower={onReachBottom}
|
||||
onScrollUpperThreshold={50}
|
||||
>
|
||||
{filteredRecords.map(record => {
|
||||
const statusInfo = getStatusInfo(record.status);
|
||||
const typeInfo = getTypeInfo(record.invoiceType);
|
||||
|
||||
return (
|
||||
<View key={record.id} className="bg-white rounded-lg p-4 mb-4">
|
||||
<View className="flex justify-between items-start mb-3">
|
||||
<View className="flex-1">
|
||||
<View className="flex items-center mb-2">
|
||||
<Text className={`text-xs px-2 py-1 rounded mr-2 ${typeInfo.bgColor} ${typeInfo.textColor}`}>
|
||||
{typeInfo.label}
|
||||
</Text>
|
||||
<Text className={`text-xs px-2 py-1 rounded mr-2 ${statusInfo.bgColor} ${statusInfo.textColor}`}>
|
||||
{statusInfo.text}
|
||||
</Text>
|
||||
</View>
|
||||
<Text className="text-lg font-medium">{record.titleName}</Text>
|
||||
{record.orderNo && (
|
||||
<Text className="text-xs text-gray-500 mt-1 block">订单号:{record.orderNo}</Text>
|
||||
)}
|
||||
</View>
|
||||
<Text className="text-xl font-bold text-red-500">{formatMoney(record.amount)}</Text>
|
||||
</View>
|
||||
|
||||
<View className="text-sm text-gray-500 flex flex-col" style={{ gap: '4px' }}>
|
||||
<View className="flex justify-between">
|
||||
<Text>申请时间</Text>
|
||||
<Text>{formatDate(record.applyTime)}</Text>
|
||||
</View>
|
||||
{record.invoiceNo && (
|
||||
<View className="flex justify-between">
|
||||
<Text>发票号</Text>
|
||||
<Text>{record.invoiceNo}</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{record.status === 2 && (
|
||||
<View className="mt-3 pt-3 border-t border-gray-100 flex justify-end">
|
||||
<View
|
||||
className="px-4 py-2 bg-blue-500 text-white rounded-full"
|
||||
onClick={() => handleViewInvoice(record)}
|
||||
>
|
||||
<Text className="text-sm">查看发票</Text>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
})}
|
||||
<LoadMore loading={loadingMore} hasMore={hasMore} />
|
||||
</ScrollView>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
297
src_bak/pages/invoice/title/index.tsx
Normal file
297
src_bak/pages/invoice/title/index.tsx
Normal file
@@ -0,0 +1,297 @@
|
||||
import { View, Text, ScrollView, Input, Button } from '@tarojs/components';
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { useDidShow } from '@tarojs/taro';
|
||||
import Taro from '@tarojs/taro';
|
||||
import NavBar from '@/components/NavBar';
|
||||
import LoadMore from '@/components/common/LoadMore';
|
||||
import EmptyState from '@/components/common/EmptyState';
|
||||
import {
|
||||
listShopInvoiceTitle,
|
||||
addShopInvoiceTitle,
|
||||
updateShopInvoiceTitle,
|
||||
removeShopInvoiceTitle,
|
||||
setDefaultInvoiceTitle
|
||||
} from '@/api/shop/shopInvoiceTitle';
|
||||
import type { ShopInvoiceTitle, ShopInvoiceTitleParam } from '@/api/shop/shopInvoiceTitle/model';
|
||||
|
||||
export default function InvoiceTitlePage() {
|
||||
const [titleList, setTitleList] = useState<ShopInvoiceTitle[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [showAddModal, setShowAddModal] = useState(false);
|
||||
const [editItem, setEditItem] = useState<ShopInvoiceTitle | null>(null);
|
||||
const [formData, setFormData] = useState({
|
||||
type: 'personal' as 'personal' | 'company',
|
||||
name: '',
|
||||
taxNumber: '',
|
||||
email: '',
|
||||
});
|
||||
|
||||
// 加载数据
|
||||
const loadData = useCallback(async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const params: ShopInvoiceTitleParam = {};
|
||||
const result = await listShopInvoiceTitle(params);
|
||||
setTitleList(result || []);
|
||||
} catch (e: any) {
|
||||
console.error('获取发票抬头失败:', e);
|
||||
Taro.showToast({ title: e.message || '获取数据失败', icon: 'none' });
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
loadData();
|
||||
}, [loadData]);
|
||||
|
||||
// 删除
|
||||
const handleDelete = async (id: number) => {
|
||||
Taro.showModal({
|
||||
title: '确认删除',
|
||||
content: '确定要删除该发票抬头吗?',
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
try {
|
||||
await removeShopInvoiceTitle(id);
|
||||
Taro.showToast({ title: '删除成功', icon: 'success' });
|
||||
loadData();
|
||||
} catch (e: any) {
|
||||
Taro.showToast({ title: e.message || '删除失败', icon: 'none' });
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 设置默认
|
||||
const handleSetDefault = async (id: number) => {
|
||||
try {
|
||||
await setDefaultInvoiceTitle(id);
|
||||
Taro.showToast({ title: '设置成功', icon: 'success' });
|
||||
loadData();
|
||||
} catch (e: any) {
|
||||
Taro.showToast({ title: e.message || '设置失败', icon: 'none' });
|
||||
}
|
||||
};
|
||||
|
||||
// 编辑
|
||||
const handleEdit = (item: ShopInvoiceTitle) => {
|
||||
setEditItem(item);
|
||||
setFormData({
|
||||
type: (item.type as 'personal' | 'company') || 'personal',
|
||||
name: item.name || '',
|
||||
taxNumber: item.taxNumber || '',
|
||||
email: item.email || '',
|
||||
});
|
||||
setShowAddModal(true);
|
||||
};
|
||||
|
||||
// 添加/编辑提交
|
||||
const handleSubmit = async () => {
|
||||
if (!formData.name.trim()) {
|
||||
Taro.showToast({ title: '请输入抬头名称', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
if (formData.type === 'company' && !formData.taxNumber.trim()) {
|
||||
Taro.showToast({ title: '请输入税号', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (editItem) {
|
||||
await updateShopInvoiceTitle({
|
||||
id: editItem.id,
|
||||
...formData,
|
||||
});
|
||||
Taro.showToast({ title: '修改成功', icon: 'success' });
|
||||
} else {
|
||||
await addShopInvoiceTitle(formData);
|
||||
Taro.showToast({ title: '添加成功', icon: 'success' });
|
||||
}
|
||||
setShowAddModal(false);
|
||||
setEditItem(null);
|
||||
setFormData({ type: 'personal', name: '', taxNumber: '', email: '' });
|
||||
loadData();
|
||||
} catch (e: any) {
|
||||
Taro.showToast({ title: e.message || '操作失败', icon: 'none' });
|
||||
}
|
||||
};
|
||||
|
||||
// 取消编辑
|
||||
const handleCancel = () => {
|
||||
setShowAddModal(false);
|
||||
setEditItem(null);
|
||||
setFormData({ type: 'personal', name: '', taxNumber: '', email: '' });
|
||||
};
|
||||
|
||||
return (
|
||||
<View className="bg-gray-100 flex flex-col" style={{ minHeight: '100vh' }}>
|
||||
<NavBar title="发票抬头管理" />
|
||||
|
||||
<View className='flex-1'>
|
||||
{loading ? (
|
||||
<LoadMore loading />
|
||||
) : titleList.length === 0 ? (
|
||||
<EmptyState message="暂无发票抬头" />
|
||||
) : (
|
||||
<ScrollView scrollY className="p-4">
|
||||
{titleList.map(item => (
|
||||
<View key={item.id} className="bg-white rounded-lg p-4 mb-4">
|
||||
<View className="flex justify-between items-start mb-2">
|
||||
<View className="flex-1">
|
||||
<View className="flex items-center mb-2">
|
||||
<Text className={`text-xs px-2 py-1 rounded mr-2 ${
|
||||
item.type === 'personal' ? 'bg-blue-100 text-blue-600' : 'bg-orange-100 text-orange-600'
|
||||
}`}>
|
||||
{item.type === 'personal' ? '个人' : '企业'}
|
||||
</Text>
|
||||
{item.isDefault === 1 && (
|
||||
<Text className="text-xs px-2 py-1 rounded bg-red-100 text-red-600">
|
||||
默认
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
<Text className="text-lg font-medium">{item.name}</Text>
|
||||
{item.type === 'company' && item.taxNumber && (
|
||||
<Text className="text-sm text-gray-500 mt-1 block">税号:{item.taxNumber}</Text>
|
||||
)}
|
||||
{item.email && (
|
||||
<Text className="text-sm text-gray-500 mt-1 block">邮箱:{item.email}</Text>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View className="flex justify-between items-center pt-3 border-t border-gray-100">
|
||||
<View
|
||||
className="flex items-center"
|
||||
onClick={() => handleSetDefault(item.id!)}
|
||||
>
|
||||
<View className={`w-5 h-5 rounded border-2 flex items-center justify-center ${
|
||||
item.isDefault === 1 ? 'bg-red-500 border-red-500' : 'border-gray-300'
|
||||
}`}>
|
||||
{item.isDefault === 1 && <Text className="text-white text-xs">✓</Text>}
|
||||
</View>
|
||||
<Text className="text-sm text-gray-600 ml-2">设为默认</Text>
|
||||
</View>
|
||||
<View className="flex" style={{ gap: '16px' }}>
|
||||
<Text
|
||||
className="text-sm text-blue-500"
|
||||
onClick={() => handleEdit(item)}
|
||||
>
|
||||
编辑
|
||||
</Text>
|
||||
<Text
|
||||
className="text-sm text-red-500"
|
||||
onClick={() => handleDelete(item.id!)}
|
||||
>
|
||||
删除
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
))}
|
||||
</ScrollView>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* 添加/编辑弹窗 */}
|
||||
{showAddModal && (
|
||||
<View className="absolute flex items-center justify-center z-50" style={{ top: 0, right: 0, bottom: 0, left: 0, backgroundColor: 'rgba(0,0,0,0.5)' }}>
|
||||
<View className="bg-white rounded-lg p-6" style={{ width: '91.667%', maxWidth: '688px' }}>
|
||||
<Text className="text-xl font-bold mb-4">{editItem ? '编辑发票抬头' : '添加发票抬头'}</Text>
|
||||
|
||||
{/* 抬头类型 */}
|
||||
<View className="mb-4">
|
||||
<Text className="text-sm text-gray-600 mb-2 block">抬头类型</Text>
|
||||
<View className="flex">
|
||||
<View
|
||||
className={`flex-1 py-2 text-center border rounded-l ${
|
||||
formData.type === 'personal' ? 'bg-red-50 border-red-500 text-red-500' : 'border-gray-300'
|
||||
}`}
|
||||
onClick={() => setFormData(prev => ({ ...prev, type: 'personal' }))}
|
||||
>
|
||||
<Text>个人</Text>
|
||||
</View>
|
||||
<View
|
||||
className={`flex-1 py-2 text-center border rounded-r ${
|
||||
formData.type === 'company' ? 'bg-red-50 border-red-500 text-red-500' : 'border-gray-300'
|
||||
}`}
|
||||
onClick={() => setFormData(prev => ({ ...prev, type: 'company' }))}
|
||||
>
|
||||
<Text>企业</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 抬头名称 */}
|
||||
<View className="mb-4">
|
||||
<Text className="text-sm text-gray-600 mb-2 block">抬头名称</Text>
|
||||
<Input
|
||||
className="border rounded px-3 py-2"
|
||||
placeholder="请输入发票抬头名称"
|
||||
value={formData.name}
|
||||
onInput={(e: any) => setFormData(prev => ({ ...prev, name: e.detail.value }))}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* 税号 */}
|
||||
{formData.type === 'company' && (
|
||||
<View className="mb-4">
|
||||
<Text className="text-sm text-gray-600 mb-2 block">税号</Text>
|
||||
<Input
|
||||
className="border rounded px-3 py-2"
|
||||
placeholder="请输入税号"
|
||||
value={formData.taxNumber}
|
||||
onInput={(e: any) => setFormData(prev => ({ ...prev, taxNumber: e.detail.value }))}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{/* 邮箱 */}
|
||||
<View className="mb-4">
|
||||
<Text className="text-sm text-gray-600 mb-2 block">接收邮箱(选填)</Text>
|
||||
<Input
|
||||
className="border rounded px-3 py-2"
|
||||
type="email"
|
||||
placeholder="用于接收电子发票"
|
||||
value={formData.email}
|
||||
onInput={(e: any) => setFormData(prev => ({ ...prev, email: e.detail.value }))}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* 按钮 */}
|
||||
<View className="flex" style={{ gap: '12px' }}>
|
||||
<Button
|
||||
className="flex-1 py-2 border border-gray-300 rounded"
|
||||
onClick={handleCancel}
|
||||
>
|
||||
取消
|
||||
</Button>
|
||||
<Button
|
||||
className="flex-1 py-2 bg-red-500 text-white rounded"
|
||||
onClick={handleSubmit}
|
||||
>
|
||||
保存
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{/* 底部添加按钮 */}
|
||||
<View className="p-4 bg-white border-t border-gray-200" style={{ paddingBottom: '20px' }}>
|
||||
<Button
|
||||
className="bg-red-500 text-white rounded-full w-full h-12"
|
||||
onClick={() => {
|
||||
setEditItem(null);
|
||||
setFormData({ type: 'personal', name: '', taxNumber: '', email: '' });
|
||||
setShowAddModal(true);
|
||||
}}
|
||||
>
|
||||
添加新抬头
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user