Files
xinlong-shop-taro/src/pages/title.tsx
赵忠林 f3886664f7 fix(api): 替换所有接口请求的域名为 guilixu-api.websoft.top
- 将获取 STS Token 的接口地址由 paopao-api 改为 guilixu-api
- 更新图片上传接口地址为新的 guilixu-api 域名
- 修改用户推广页面中邀请码链接和二维码接口的域名
- 更改注册页微信登录接口请求的域名为 guilixu-api
2026-06-16 17:15:59 +08:00

298 lines
10 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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>
);
}