Files
pda-cli/src/pages/storefabric/storeFabricBusinessOutList.vue
T

549 lines
16 KiB
Vue

<template>
<view>
<view class="filterBar">
<u-search
v-model="filters.order_no"
placeholder="出仓单号"
:show-action="false"
@search="applySearch"
@custom="applySearch"
@clear="applySearch"
/>
<view class="filterBtn" :class="{ 'filterBtn--active': hasActiveFilter }" @click="filterShow = true">
<view class="filterBtn__icon">
<u-icon name="list" size="44" :color="hasActiveFilter ? '#2979ff' : '#666'"></u-icon>
<view v-if="hasActiveFilter" class="filterBtn__badge"></view>
</view>
<text>筛选</text>
</view>
</view>
<scroll-view scroll-y :style="{ height: scrollHeight }" refresher-enabled
:refresher-triggered="triggered" @refresherrefresh="onRefresh">
<dataNull v-if="list.length === 0" src="/src/static/img/chahua/gjNull.png"
title="暂无坯布出仓单" title1="请点击右下角按钮新增">
</dataNull>
<view v-for="(item, index) in list" :key="item.id" @click="goView(item)">
<FabricOutItem :item="item" :index="index" />
</view>
</scroll-view>
<addBtn url="./storeFabricBusinessOutAdd"></addBtn>
<u-popup v-model="filterShow" mode="right" width="580rpx" :safe-area-inset-bottom="true" @close="cancelFilterEdit">
<view class="filterPanel">
<view class="filterTitle">筛选条件</view>
<view class="filterItem">
<text class="filterLabel">出仓单号</text>
<view class="filterInput">
<u-input
v-model="filters.order_no"
placeholder="请输入出仓单号"
:height="100"
:custom-style="{ fontSize: '36rpx', color: '#202328' }"
placeholder-style="color: #aeb4bf; font-size: 34rpx;"
/>
</view>
</view>
<view class="filterItem">
<text class="filterLabel">出仓日期</text>
<view class="dateRow">
<picker class="datePicker" mode="date" :value="filters.start_date" @change="e => filters.start_date = e.detail.value">
<view class="dateInput" :class="{ 'dateInput--placeholder': !filters.start_date }">
{{ filters.start_date || '开始日期' }}
</view>
</picker>
<text class="dateSeparator">~</text>
<picker class="datePicker" mode="date" :value="filters.end_date" @change="e => filters.end_date = e.detail.value">
<view class="dateInput" :class="{ 'dateInput--placeholder': !filters.end_date }">
{{ filters.end_date || '结束日期' }}
</view>
</picker>
</view>
</view>
<view class="filterItem" @click="openDeliveryUnitSelect">
<text class="filterLabel">出仓单位</text>
<view class="filterValue">{{ deliveryUnitLabel || '全部' }} <u-icon name="arrow-right" size="36"></u-icon></view>
</view>
<view class="filterItem" @click="openBusinessUnitSelect">
<text class="filterLabel">接收单位</text>
<view class="filterValue">{{ businessUnitLabel || '全部' }} <u-icon name="arrow-right" size="36"></u-icon></view>
</view>
<view class="filterItem" @click="openStatusSelect">
<text class="filterLabel">订单状态</text>
<view class="filterValue">{{ statusLabel || '全部' }} <u-icon name="arrow-right" size="36"></u-icon></view>
</view>
<view class="filterActions">
<u-button type="warning" size="medium" @click="resetFilter">重置</u-button>
<u-button type="primary" size="medium" @click="applyFilter">确定</u-button>
</view>
</view>
</u-popup>
<u-select
class="pdaSelect"
v-model="statusSelectShow"
title="选择订单状态"
:list="statusSelectList"
:default-value="statusSelectDefault"
@confirm="onStatusConfirm"
></u-select>
<u-select
class="pdaSelect"
v-model="unitSelectShow"
title="选择出仓单位"
:list="unitSelectList"
:default-value="unitSelectDefault"
@confirm="onUnitConfirm"
></u-select>
<search-select-popup
:show.sync="businessUnitSelectShow"
title="选择接收单位"
placeholder="请输入染厂名称"
:list="businessUnitSelectList"
@confirm="onBusinessUnitConfirm"
/>
</view>
</template>
<script>
import addBtn from '@/components/addBtn/addBtn.vue';
import FabricOutItem from '@/components/card/storeFabricBusinessOutItem.vue';
import SearchSelectPopup from '@/components/storefabric/SearchSelectPopup.vue';
import {
getStatusOptions,
AUDIT_STATUS,
AUDIT_STATUS_MAP,
BILL_TYPES,
BUSINESS_UNIT_TYPE_DYEING_FACTORY,
formatRoll,
mapToSelectOptions,
fetchAllOrderList,
} from '@/common/storeFabricBusinessOut';
const FILTER_STORAGE_KEY = 'storeFabricBusinessOutListFilters';
const createDefaultFilters = () => ({
order_no: '',
start_date: '',
end_date: '',
delivery_unit_id: '',
delivery_unit_name: '',
business_unit_id: '',
business_unit_name: '',
audit_status: AUDIT_STATUS.PENDING,
});
const normalizeFilters = (value) => {
const filters = createDefaultFilters();
if (!value || typeof value !== 'object' || Array.isArray(value)) return filters;
Object.keys(filters).forEach((key) => {
if (typeof value[key] === 'string' || typeof value[key] === 'number') {
filters[key] = value[key];
}
});
if (!filters.delivery_unit_id) filters.delivery_unit_name = '';
if (!filters.business_unit_id) filters.business_unit_name = '';
return filters;
};
export default {
components: { addBtn, FabricOutItem, SearchSelectPopup },
data() {
return {
list: [],
scrollHeight: '667px',
triggered: false,
filterShow: false,
statusSelectShow: false,
unitSelectShow: false,
businessUnitSelectShow: false,
unitSelectType: '',
deliveryUnitOptions: [],
businessUnitOptions: [],
unitOptionsLoading: false,
billTypeName: (BILL_TYPES[0] || {}).label || '坯布其他出货单',
filters: createDefaultFilters(),
appliedFilters: createDefaultFilters(),
statusSelectList: [
{ value: '', label: '全部' },
...getStatusOptions(),
],
};
},
computed: {
statusLabel() {
if (this.filters.audit_status === '' || this.filters.audit_status === null) return '';
return AUDIT_STATUS_MAP[Number(this.filters.audit_status)] || '';
},
deliveryUnitLabel() {
return this.filters.delivery_unit_name || '';
},
businessUnitLabel() {
return this.filters.business_unit_name || '';
},
unitSelectList() {
return [{ value: '', label: '全部' }, ...this.deliveryUnitOptions];
},
businessUnitSelectList() {
return [{ value: '', label: '全部' }, ...this.businessUnitOptions];
},
statusSelectDefault() {
const index = this.statusSelectList.findIndex(
(item) => String(item.value) === String(this.filters.audit_status)
);
return [index >= 0 ? index : 0];
},
unitSelectDefault() {
const index = this.unitSelectList.findIndex(
(item) => String(item.value) === String(this.filters.delivery_unit_id)
);
return [index >= 0 ? index : 0];
},
hasActiveFilter() {
const filters = this.appliedFilters;
return Boolean(
String(filters.order_no || '').trim()
|| filters.start_date
|| filters.end_date
|| filters.delivery_unit_id
|| filters.business_unit_id
|| (filters.audit_status !== '' && filters.audit_status !== null)
);
},
},
onLoad() {
uni.setNavigationBarTitle({ title: '坯布出库列表' });
this.restoreFilterCache();
uni.getSystemInfo({
success: (res) => {
this.scrollHeight = `${res.windowHeight - 50}px`;
},
});
},
onShow() {
this.loadList();
},
methods: {
restoreFilterCache() {
try {
const filters = normalizeFilters(uni.getStorageSync(FILTER_STORAGE_KEY));
this.filters = { ...filters };
this.appliedFilters = { ...filters };
} catch (e) {
this.filters = createDefaultFilters();
this.appliedFilters = createDefaultFilters();
}
},
saveFilterCache() {
try {
uni.setStorageSync(FILTER_STORAGE_KEY, { ...this.appliedFilters });
} catch (e) {
// 缓存失败不影响列表筛选
}
},
commitFilters() {
const filters = normalizeFilters(this.filters);
this.filters = { ...filters };
this.appliedFilters = { ...filters };
this.saveFilterCache();
this.loadList();
},
applySearch() {
this.commitFilters();
},
cancelFilterEdit() {
this.filters = { ...this.appliedFilters };
},
loadDeliveryUnitOptions() {
if (this.deliveryUnitOptions.length) return Promise.resolve(this.deliveryUnitOptions);
return this.$u.api.businessUnit.list({})
.then((res) => {
this.deliveryUnitOptions = mapToSelectOptions(res);
return this.deliveryUnitOptions;
})
.catch(() => {
this.deliveryUnitOptions = [];
return this.deliveryUnitOptions;
});
},
loadBusinessUnitOptions() {
if (this.businessUnitOptions.length) return Promise.resolve(this.businessUnitOptions);
return this.$u.api.businessUnit.list({ unit_type_id: BUSINESS_UNIT_TYPE_DYEING_FACTORY })
.then((res) => {
this.businessUnitOptions = mapToSelectOptions(res);
return this.businessUnitOptions;
})
.catch(() => {
this.businessUnitOptions = [];
return this.businessUnitOptions;
});
},
openUnitSelect(type) {
if (this.unitOptionsLoading) return;
this.unitOptionsLoading = true;
const loadFn = type === 'delivery' ? this.loadDeliveryUnitOptions : this.loadBusinessUnitOptions;
loadFn.call(this)
.then((list) => {
if (!list.length) {
uni.showToast({ title: '暂无可选单位', icon: 'none' });
return;
}
this.unitSelectType = type;
this.unitSelectShow = true;
})
.finally(() => {
this.unitOptionsLoading = false;
});
},
openDeliveryUnitSelect() {
this.openUnitSelect('delivery');
},
openBusinessUnitSelect() {
if (this.unitOptionsLoading) return;
this.unitOptionsLoading = true;
this.loadBusinessUnitOptions()
.then((list) => {
if (!list.length) {
uni.showToast({ title: '暂无可选单位', icon: 'none' });
return;
}
this.businessUnitSelectShow = true;
})
.finally(() => {
this.unitOptionsLoading = false;
});
},
onBusinessUnitConfirm(item) {
this.filters.business_unit_id = item.value;
this.filters.business_unit_name = item.value ? item.label : '';
},
onUnitConfirm(e) {
const item = e[0] || {};
if (this.unitSelectType === 'delivery') {
this.filters.delivery_unit_id = item.value;
this.filters.delivery_unit_name = item.value ? item.label : '';
} else {
this.filters.business_unit_id = item.value;
this.filters.business_unit_name = item.value ? item.label : '';
}
},
loadList() {
const filters = this.appliedFilters;
const params = {};
if (filters.order_no) params.order_no = filters.order_no;
if (filters.audit_status !== '' && filters.audit_status !== null) {
params.audit_status = filters.audit_status;
}
fetchAllOrderList((p) => this.$u.api.gfmOtherDeliveryOrder.list(p), params)
.then((rows) => {
this.triggered = false;
this.list = rows.map(this.mapToCard).filter(this.matchClientFilter);
})
.catch((err) => {
this.triggered = false;
this.list = [];
uni.showToast({ title: err.message || '加载失败', icon: 'none' });
});
},
mapToCard(order) {
return {
id: order.id,
order_no: order.order_no || '',
out_date: (order.delivery_time || '').slice(0, 10),
bill_type_name: this.billTypeName,
delivery_unit_id: order.delivery_unit_id || '',
delivery_unit_name: order.delivery_unit_name || '',
business_unit_id: order.business_unit_id || '',
business_unit_name: order.business_unit_name || '',
create_user_name: order.creator_name || '',
create_time: order.create_time || '',
auditor_name: order.auditer_name || '',
audit_date: order.audit_time || '',
audit_status: order.audit_status,
audit_status_name: order.audit_status_name || AUDIT_STATUS_MAP[order.audit_status] || '',
total_roll: formatRoll(order.total_roll),
};
},
// 后端列表仅支持 单号/状态 过滤,出仓日期与单位在前端做本地过滤
matchClientFilter(item) {
const filters = this.appliedFilters;
if (filters.start_date && item.out_date < filters.start_date) return false;
if (filters.end_date && item.out_date > filters.end_date) return false;
if (filters.delivery_unit_id && String(item.delivery_unit_id) !== String(filters.delivery_unit_id)) {
return false;
}
if (filters.business_unit_id && String(item.business_unit_id) !== String(filters.business_unit_id)) {
return false;
}
return true;
},
onRefresh() {
this.triggered = true;
this.loadList();
},
goView(item) {
const page = Number(item.audit_status) === AUDIT_STATUS.PENDING
? 'storeFabricBusinessOutEdit'
: 'storeFabricBusinessOutView';
uni.navigateTo({ url: `./${page}?id=${item.id}` });
},
openStatusSelect() { this.statusSelectShow = true; },
onStatusConfirm(e) { this.filters.audit_status = e[0].value; },
resetFilter() {
this.filters = createDefaultFilters();
},
applyFilter() {
this.commitFilters();
this.filterShow = false;
},
},
};
</script>
<style lang="scss">
@import '@/common/pda-typography.scss';
page { background-color: #F8F8F8; }
.filterBar { display: flex; align-items: center; padding: 16rpx 20rpx; background: #fff; gap: 16rpx; }
.filterBtn {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-width: 88rpx;
min-height: 76rpx;
padding: 6rpx 8rpx;
border: 2rpx solid transparent;
border-radius: 10rpx;
box-sizing: border-box;
font-size: $pda-font-nav-sub;
line-height: 1.2;
color: #666;
transition: color 0.2s, background-color 0.2s, border-color 0.2s;
}
.filterBtn--active {
color: #2979ff;
background: #eef5ff;
border-color: #9fc5ff;
}
.filterBtn__icon {
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.filterBtn__badge {
position: absolute;
top: -3rpx;
right: -7rpx;
width: 13rpx;
height: 13rpx;
border: 3rpx solid #fff;
border-radius: 50%;
background: #ff4d4f;
box-sizing: content-box;
}
.filterPanel {
min-height: 100%;
padding: 32rpx 28rpx;
box-sizing: border-box;
}
.filterTitle {
margin-bottom: 30rpx;
font-size: $pda-font-popup-title;
font-weight: bold;
color: #202328;
}
.filterItem { margin-bottom: 28rpx; }
.filterLabel {
display: block;
margin-bottom: 14rpx;
font-size: $pda-font-body;
line-height: 1.35;
color: #555b66;
}
.filterInput {
display: flex;
align-items: center;
min-height: $pda-row-min-height;
padding: 0 18rpx;
background: #f5f6f8;
border-radius: 8rpx;
box-sizing: border-box;
}
::v-deep .filterInput .u-input__input {
font-size: $pda-font-body !important;
color: #202328;
}
::v-deep .filterInput .u-input__input::placeholder {
font-size: $pda-font-placeholder;
color: #aeb4bf;
}
.filterValue {
display: flex;
align-items: center;
justify-content: space-between;
min-height: $pda-row-min-height;
padding: 0 18rpx;
background: #f5f6f8;
border-radius: 8rpx;
box-sizing: border-box;
font-size: $pda-font-body;
color: #202328;
}
.dateRow {
display: flex;
align-items: center;
gap: 10rpx;
}
.datePicker {
flex: 1;
min-width: 0;
}
.dateInput {
display: flex;
align-items: center;
justify-content: center;
min-height: $pda-row-min-height;
padding: 0 8rpx;
background: #f5f6f8;
border-radius: 8rpx;
box-sizing: border-box;
font-size: $pda-font-body;
color: #202328;
text-align: center;
white-space: nowrap;
}
.dateInput--placeholder {
font-size: $pda-font-placeholder;
color: #7d8490;
}
.dateSeparator {
flex-shrink: 0;
font-size: $pda-font-body;
color: #555b66;
}
.filterActions {
display: flex;
gap: 20rpx;
margin-top: 40rpx;
}
.filterActions .u-btn {
flex: 1;
height: $pda-button-height !important;
line-height: $pda-button-height !important;
padding: 0 !important;
font-size: $pda-font-button !important;
}
::v-deep .pdaSelect .u-select__header {
height: $pda-row-min-height;
}
::v-deep .pdaSelect .u-select__header__btn,
::v-deep .pdaSelect .u-select__header__title,
::v-deep .pdaSelect .u-select__body__picker-view__item {
font-size: $pda-font-popup-item !important;
}
</style>