商品列表状态保存
This commit is contained in:
+18
-89
@@ -4,11 +4,6 @@
|
||||
padding: 20rpx 24rpx 60rpx;
|
||||
box-sizing: border-box;
|
||||
|
||||
// 多选模式为底部导出栏留出空间
|
||||
&--select {
|
||||
padding-bottom: 160rpx;
|
||||
}
|
||||
|
||||
// 底部待支付汇总栏留出空间
|
||||
&--pay {
|
||||
padding-bottom: 180rpx;
|
||||
@@ -55,7 +50,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 状态筛选 + 导出入口 =====
|
||||
// ===== 状态筛选 =====
|
||||
.bill-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -67,22 +62,6 @@
|
||||
white-space: nowrap;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&__export {
|
||||
flex-shrink: 0;
|
||||
margin-left: 16rpx;
|
||||
padding: 12rpx 28rpx;
|
||||
border-radius: 999rpx;
|
||||
background: #fff;
|
||||
border: 1rpx solid #ee0a24;
|
||||
color: #ee0a24;
|
||||
font-size: 26rpx;
|
||||
|
||||
&.active {
|
||||
background: #ee0a24;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.status-scroll {
|
||||
@@ -132,11 +111,6 @@
|
||||
padding: 24rpx;
|
||||
margin-bottom: 16rpx;
|
||||
|
||||
&--select {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__content {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
@@ -192,7 +166,24 @@
|
||||
font-size: 32rpx;
|
||||
color: #323233;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
// 右侧栏:金额 + 导出按钮
|
||||
&__side {
|
||||
margin-left: 20rpx;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
&__export {
|
||||
margin-top: 12rpx;
|
||||
padding: 6rpx 24rpx;
|
||||
border-radius: 999rpx;
|
||||
border: 1rpx solid #ee0a24;
|
||||
color: #ee0a24;
|
||||
font-size: 22rpx;
|
||||
}
|
||||
|
||||
&__footer {
|
||||
@@ -213,68 +204,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 勾选圆圈 =====
|
||||
.bill-check {
|
||||
width: 36rpx;
|
||||
height: 36rpx;
|
||||
border-radius: 50%;
|
||||
border: 2rpx solid #c8c9cc;
|
||||
margin-right: 20rpx;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
|
||||
&.on {
|
||||
background: #ee0a24;
|
||||
border-color: #ee0a24;
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 导出操作栏 =====
|
||||
.export-bar {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 99;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 16rpx 24rpx calc(16rpx + env(safe-area-inset-bottom));
|
||||
background: #fff;
|
||||
box-shadow: 0 -2rpx 12rpx rgba(0, 0, 0, 0.06);
|
||||
|
||||
&__count {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
font-size: 26rpx;
|
||||
color: #646566;
|
||||
}
|
||||
|
||||
&__all {
|
||||
padding: 12rpx 24rpx;
|
||||
margin-right: 16rpx;
|
||||
border: 1rpx solid #dcdee0;
|
||||
border-radius: 999rpx;
|
||||
font-size: 26rpx;
|
||||
color: #323233;
|
||||
}
|
||||
|
||||
&__btn {
|
||||
padding: 14rpx 40rpx;
|
||||
border-radius: 999rpx;
|
||||
background: #ee0a24;
|
||||
color: #fff;
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
|
||||
&.disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 分类选择弹层 =====
|
||||
.category-popup {
|
||||
padding: 32rpx 32rpx 24rpx;
|
||||
|
||||
+31
-94
@@ -11,9 +11,6 @@ import './index.less'
|
||||
|
||||
const PAGE_SIZE = 10
|
||||
|
||||
/** 单次导出上限(后端限制 1~100 张) */
|
||||
const EXPORT_MAX = 100
|
||||
|
||||
/** 状态筛选(接口 status 为原始支付状态:0 未支付含审核中 / 1 已支付) */
|
||||
const STATUS_FILTERS: Array<{ value: 0 | 1 | undefined; label: string }> = [
|
||||
{ value: undefined, label: '全部' },
|
||||
@@ -30,7 +27,7 @@ interface CategoryOption {
|
||||
/**
|
||||
* 账单列表页
|
||||
* 采购单完成后由后台按门店生成(只读);底部汇总栏为门店口径待支付汇总(含审核中,不受筛选影响)
|
||||
* 支持多选账单合并导出 Excel(可按一级分类过滤商品明细)
|
||||
* 每个账单可单独导出 Excel(可按一级分类过滤商品明细),不支持合并导出
|
||||
*/
|
||||
export default function BillListPage() {
|
||||
const token = useAuthStore(s => s.token)
|
||||
@@ -43,9 +40,8 @@ export default function BillListPage() {
|
||||
const [finished, setFinished] = useState(false)
|
||||
const loadingRef = useRef(false)
|
||||
|
||||
/** 导出:多选模式 + 已选账单 + 分类弹层 */
|
||||
const [selectMode, setSelectMode] = useState(false)
|
||||
const [selectedIds, setSelectedIds] = useState<number[]>([])
|
||||
/** 导出:待导出账单 + 分类弹层 */
|
||||
const [exportBill, setExportBill] = useState<Bill | null>(null)
|
||||
const [showCategory, setShowCategory] = useState(false)
|
||||
const [categories, setCategories] = useState<CategoryOption[]>([])
|
||||
|
||||
@@ -107,49 +103,9 @@ export default function BillListPage() {
|
||||
Taro.navigateTo({ url: '/pages/payment/index' })
|
||||
}, [])
|
||||
|
||||
/** 进入/退出多选导出模式 */
|
||||
const toggleSelectMode = useCallback(() => {
|
||||
setSelectMode(prev => !prev)
|
||||
setSelectedIds([])
|
||||
}, [])
|
||||
|
||||
/** 账单点击:多选模式切换勾选,否则进详情 */
|
||||
const handleItemTap = useCallback(
|
||||
(bill: Bill) => {
|
||||
if (!selectMode) {
|
||||
goDetail(bill.id)
|
||||
return
|
||||
}
|
||||
setSelectedIds(prev => {
|
||||
if (prev.includes(bill.id)) return prev.filter(i => i !== bill.id)
|
||||
if (prev.length >= EXPORT_MAX) {
|
||||
Taro.showToast({ title: `最多导出 ${EXPORT_MAX} 张`, icon: 'none' })
|
||||
return prev
|
||||
}
|
||||
return [...prev, bill.id]
|
||||
})
|
||||
},
|
||||
[selectMode, goDetail],
|
||||
)
|
||||
|
||||
/** 全选当前已加载账单(受导出上限约束) */
|
||||
const handleSelectAll = useCallback(() => {
|
||||
setSelectedIds(prev => {
|
||||
if (prev.length === bills.length) return []
|
||||
if (bills.length > EXPORT_MAX) {
|
||||
Taro.showToast({ title: `最多导出 ${EXPORT_MAX} 张,已选前 ${EXPORT_MAX} 张`, icon: 'none' })
|
||||
return bills.slice(0, EXPORT_MAX).map(b => b.id)
|
||||
}
|
||||
return bills.map(b => b.id)
|
||||
})
|
||||
}, [bills])
|
||||
|
||||
/** 打开分类选择弹层(首次加载分类树根节点) */
|
||||
const handleExportTap = useCallback(async () => {
|
||||
if (selectedIds.length === 0) {
|
||||
Taro.showToast({ title: '请先勾选要导出的账单', icon: 'none' })
|
||||
return
|
||||
}
|
||||
const handleExportTap = useCallback(
|
||||
async (bill: Bill) => {
|
||||
if (categories.length === 0) {
|
||||
try {
|
||||
const res = await getCategoriesApi()
|
||||
@@ -161,18 +117,21 @@ export default function BillListPage() {
|
||||
return // 错误已由 request 层 toast
|
||||
}
|
||||
}
|
||||
setExportBill(bill)
|
||||
setShowCategory(true)
|
||||
}, [selectedIds, categories])
|
||||
},
|
||||
[categories],
|
||||
)
|
||||
|
||||
/** 按所选分类导出合并 Excel */
|
||||
/** 按所选分类导出单个账单 Excel */
|
||||
const handleExport = useCallback(
|
||||
async (categoryId: number) => {
|
||||
if (!exportBill) return
|
||||
const isH5 = process.env.TARO_ENV === 'h5'
|
||||
Taro.showLoading({ title: '导出中...', mask: true })
|
||||
try {
|
||||
await downloadExportFile(getBillExportUrl(selectedIds, categoryId), '门店账单.xlsx')
|
||||
await downloadExportFile(getBillExportUrl(exportBill.id, categoryId), `账单-${exportBill.bill_no}.xlsx`)
|
||||
setShowCategory(false)
|
||||
toggleSelectMode()
|
||||
if (isH5) {
|
||||
Taro.showToast({ title: '导出成功', icon: 'success' })
|
||||
}
|
||||
@@ -182,15 +141,15 @@ export default function BillListPage() {
|
||||
Taro.hideLoading()
|
||||
}
|
||||
},
|
||||
[selectedIds, toggleSelectMode],
|
||||
[exportBill],
|
||||
)
|
||||
|
||||
/** 底部待支付汇总栏是否可见(多选导出时让位给导出栏) */
|
||||
const showPayBar = loggedIn && !selectMode && !!summary && summary.unpaid_count > 0
|
||||
/** 底部待支付汇总栏是否可见 */
|
||||
const showPayBar = loggedIn && !!summary && summary.unpaid_count > 0
|
||||
|
||||
return (
|
||||
<View className={`bill-page ${selectMode ? 'bill-page--select' : ''} ${showPayBar ? 'bill-page--pay' : ''}`}>
|
||||
{/* ========== 状态筛选 + 导出入口 ========== */}
|
||||
<View className={`bill-page ${showPayBar ? 'bill-page--pay' : ''}`}>
|
||||
{/* ========== 状态筛选 ========== */}
|
||||
<View className='bill-toolbar'>
|
||||
<ScrollView scrollX className='status-scroll'>
|
||||
{STATUS_FILTERS.map(item => (
|
||||
@@ -203,11 +162,6 @@ export default function BillListPage() {
|
||||
</View>
|
||||
))}
|
||||
</ScrollView>
|
||||
{loggedIn && bills.length > 0 && (
|
||||
<View className={`bill-toolbar__export ${selectMode ? 'active' : ''}`} onClick={toggleSelectMode}>
|
||||
<Text>{selectMode ? '取消' : '导出'}</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* ========== 账单列表 ========== */}
|
||||
@@ -222,19 +176,8 @@ export default function BillListPage() {
|
||||
<Empty description='暂无账单' className='bill-empty' />
|
||||
)
|
||||
) : (
|
||||
bills.map(bill => {
|
||||
const checked = selectMode && selectedIds.includes(bill.id)
|
||||
return (
|
||||
<View
|
||||
key={bill.id}
|
||||
className={`bill-item ${selectMode ? 'bill-item--select' : ''}`}
|
||||
onClick={() => handleItemTap(bill)}
|
||||
>
|
||||
{selectMode && (
|
||||
<View className={`bill-check ${checked ? 'on' : ''}`}>
|
||||
{checked && <Icon name='success' size={14} color='#fff' />}
|
||||
</View>
|
||||
)}
|
||||
bills.map(bill => (
|
||||
<View key={bill.id} className='bill-item' onClick={() => goDetail(bill.id)}>
|
||||
<View className='bill-item__content'>
|
||||
<View className='bill-item__header'>
|
||||
<Text className='bill-item__no'>{bill.bill_no}</Text>
|
||||
@@ -249,7 +192,18 @@ export default function BillListPage() {
|
||||
<Text className='bill-item__purchase'>采购单 {bill.purchase.purchase_no}</Text>
|
||||
)}
|
||||
</View>
|
||||
<View className='bill-item__side'>
|
||||
<Text className='bill-item__amount'>¥{bill.total_amount}</Text>
|
||||
<View
|
||||
className='bill-item__export'
|
||||
onClick={e => {
|
||||
e.stopPropagation()
|
||||
handleExportTap(bill)
|
||||
}}
|
||||
>
|
||||
导出
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<View className='bill-item__footer'>
|
||||
<Text className='bill-item__settle'>应结算 {bill.settlement_date}</Text>
|
||||
@@ -259,8 +213,7 @@ export default function BillListPage() {
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
})
|
||||
))
|
||||
)}
|
||||
|
||||
{loggedIn && finished && bills.length > 0 && (
|
||||
@@ -278,22 +231,6 @@ export default function BillListPage() {
|
||||
</View>
|
||||
)}
|
||||
|
||||
{/* ========== 导出操作栏 ========== */}
|
||||
{selectMode && (
|
||||
<View className='export-bar'>
|
||||
<Text className='export-bar__count'>已选 {selectedIds.length} 张</Text>
|
||||
<View className='export-bar__all' onClick={handleSelectAll}>
|
||||
{selectedIds.length === bills.length && bills.length > 0 ? '取消全选' : '全选'}
|
||||
</View>
|
||||
<View
|
||||
className={`export-bar__btn ${selectedIds.length === 0 ? 'disabled' : ''}`}
|
||||
onClick={handleExportTap}
|
||||
>
|
||||
导出 Excel
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{/* ========== 分类选择弹层 ========== */}
|
||||
<Popup
|
||||
show={showCategory}
|
||||
|
||||
@@ -123,9 +123,9 @@ export function getBillDetailApi(id: number) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 账单合并导出文件地址:GET /mini/bill/export
|
||||
* 单个账单导出文件地址:GET /mini/bill/{id}/export
|
||||
* 返回 xlsx 文件流(非 JSON,需带 token 下载);categoryId 仅过滤商品明细,费用仍全额汇总
|
||||
*/
|
||||
export function getBillExportUrl(ids: number[], categoryId = 0): string {
|
||||
return `${BASE_URL}/mini/bill/export?ids=${ids.join(',')}&category_id=${categoryId}`
|
||||
export function getBillExportUrl(id: number, categoryId = 0): string {
|
||||
return `${BASE_URL}/mini/bill/${id}/export?category_id=${categoryId}`
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@ const LOGIN_PATH = '/pages/login/index'
|
||||
/** 默认请求超时(ms) */
|
||||
const DEFAULT_TIMEOUT = 15000
|
||||
/** 接口根地址(uploadFile 等原生请求同样使用) */
|
||||
// export const BASE_URL = "http://localhost:8000"
|
||||
export const BASE_URL = "https://purchase.henanklkj.com/index.php"
|
||||
export const BASE_URL = "http://localhost:8000"
|
||||
// export const BASE_URL = "https://purchase.henanklkj.com/index.php"
|
||||
|
||||
/**
|
||||
* HTTP 状态码 → 错误提示映射
|
||||
|
||||
Reference in New Issue
Block a user