| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517 |
- <template>
- <view class="page-wrap">
- <!-- <cu-custom :backUrl="'/pages/index/index'" :isBack="true" bgColor="bg-gradual-blue">
- <block slot="content">库存列表</block>
- </cu-custom> -->
- <view class="search-panel">
- <u-search :show-action="false" v-model="searchForm.tradeName" placeholder="搜索商品名称"
- @search="refreshList" @clear="refreshList"></u-search>
- <view class="filter-row">
- <view class="filter-item" @tap="openTypePicker">
- <text class="filter-label">入库类型</text>
- <text class="filter-value">{{ searchForm.wareHouseTypeName || '全部' }}</text>
- </view>
- <view class="filter-item" @tap="openSupplierPicker">
- <text class="filter-label">供应商</text>
- <text class="filter-value">{{ searchForm.supplierName || '全部' }}</text>
- </view>
- </view>
- <view class="action-row">
- <el-button class="action-button" type="primary" @click="refreshList">查询</el-button>
- <el-button class="action-button" plain @click="resetSearch">重置</el-button>
- </view>
- </view>
- <view class="summary-row">
- <text>共 {{ tablePage.total }} 条库存</text>
- <text v-if="loading">加载中...</text>
- </view>
- <view v-if="!loading && dataList.length === 0" class="empty-state">暂无库存数据</view>
- <view v-for="(item, index) in dataList" :key="item.id || item.tradeName + item.wareHouseType + index"
- class="stock-card">
- <view class="card-head">
- <view class="goods-name">{{ item.tradeName || '-' }}</view>
- <view class="type-badge">{{ item.wareHouseTypeName || '-' }}</view>
- </view>
- <view class="stock-main">
- <view class="stock-number">
- <text class="number-label">剩余量:</text>
- <text class="number-value">{{ formatNumber(item.tradeNumber) }}</text>
- <!-- <text class="number-unit">{{ item.company || '' }}</text> -->
- </view>
- <view class="stock-total">
- <text>总量: {{ formatNumber(item.allNumber) }}</text>
- <text>单位: {{ item.company || '-' }}</text>
- </view>
- </view>
- <view class="metric-grid">
- <view class="metric-item">
- <text class="metric-label">领用量</text>
- <text class="metric-value">{{ calcBorrowNumber(item) }}</text>
- </view>
- <view class="metric-item">
- <text class="metric-label">报损量</text>
- <text class="metric-value">{{ calcLossNumber(item) }}</text>
- </view>
- <view class="metric-item">
- <text class="metric-label">提醒数量</text>
- <u--input class="warn-input" v-model="item.warnNum" placeholder="0" @blur="changeWarnNum(item)">
- </u--input>
- </view>
- <view class="metric-item">
- <text class="metric-label">是否提醒</text>
- <el-switch :value="item.warnFlag === '1'" active-color="#13ce66" inactive-color="#ff4949"
- @change="updateWarnFlag(item)">
- </el-switch>
- </view>
- </view>
- <view class="card-actions">
- <el-button class="card-button" type="primary" plain @click="openHistory(item)">查看记录</el-button>
- </view>
- </view>
- <view v-if="dataList.length" class="load-more">
- <text v-if="loadingMore">加载中...</text>
- <text v-else-if="dataList.length >= tablePage.total">没有更多了</text>
- <text v-else @tap="loadMore">加载更多</text>
- </view>
- <ba-tree-picker ref="typePicker" :multiple="false" @select-change="selectTypeChange" title="类型选择"
- :localdata="typeTree" valueKey="value" textKey="label" childrenKey="children" />
- <ware-house-supplier-picker ref="supplierPicker" @selected="selectSupplier" @clear="clearSupplier">
- </ware-house-supplier-picker>
- <ware-house-history-panel ref="historyPanel"></ware-house-history-panel>
- <edit-trade-name-dialog ref="editTradeNameDialog" @success="refreshList"></edit-trade-name-dialog>
- </view>
- </template>
- <script>
- import baTreePicker from '@/components/ba-tree-picker/ba-tree-picker.vue'
- import WareHouseService from '@/api/psi/WareHouseService'
- import MaterialTypeService from '@/api/psi/MaterialTypeService'
- import WareHouseSupplierPicker from './WareHouseSupplierPicker.vue'
- import WareHouseHistoryPanel from './WareHouseHistoryPanel.vue'
- import EditTradeNameDialog from './EditTradeNameDialog.vue'
- export default {
- name: 'WareHouseSummaryList',
- components: {
- baTreePicker,
- WareHouseSupplierPicker,
- WareHouseHistoryPanel,
- EditTradeNameDialog
- },
- data() {
- return {
- loading: false,
- loadingMore: false,
- searchForm: {
- wareHouseType: '',
- wareHouseTypeName: '',
- tradeName: '',
- supplierId: '',
- supplierName: ''
- },
- dataList: [],
- tablePage: {
- total: 0,
- currentPage: 1,
- pageSize: 10,
- orders: []
- },
- typeTree: []
- }
- },
- wareHouseService: null,
- materialTypeService: null,
- created() {
- this.wareHouseService = new WareHouseService()
- this.materialTypeService = new MaterialTypeService()
- this.loadTypeTree()
- this.refreshList()
- },
- onPullDownRefresh() {
- this.refreshList().finally(() => {
- uni.stopPullDownRefresh()
- })
- },
- onReachBottom() {
- this.loadMore()
- },
- methods: {
- async loadTypeTree() {
- try {
- const data = await this.materialTypeService.summaryTreeData({
- type: 'last'
- })
- this.typeTree = this.normalizeTree(data || [])
- } catch (e) {
- try {
- const data = await this.materialTypeService.cgList()
- this.typeTree = this.buildTree(data || [])
- } catch (error) {
- this.typeTree = []
- }
- }
- },
- normalizeTree(nodes) {
- return (nodes || []).map(item => ({
- ...item,
- value: item.value || item.id,
- label: item.label || item.name,
- children: this.normalizeTree(item.children || [])
- }))
- },
- buildTree(nodes, parentId = '0') {
- const tree = []
- for (const node of nodes || []) {
- if (node.parentId === parentId) {
- const children = this.buildTree(nodes, node.id)
- const treeNode = {
- ...node,
- value: node.value || node.id,
- label: node.label || node.name
- }
- if (children.length) {
- treeNode.children = children
- }
- tree.push(treeNode)
- }
- }
- return tree
- },
- getSearchParams() {
- return {
- wareHouseType: this.searchForm.wareHouseType,
- tradeName: this.searchForm.tradeName,
- supplierId: this.searchForm.supplierId,
- supplierName: this.searchForm.supplierName
- }
- },
- async refreshList() {
- this.tablePage.currentPage = 1
- this.loading = true
- try {
- const data = await this.wareHouseService.wareHouseSummaryList({
- current: this.tablePage.currentPage,
- size: this.tablePage.pageSize,
- orders: this.tablePage.orders,
- ...this.getSearchParams()
- })
- this.dataList = (data && data.records) || []
- this.tablePage.total = (data && data.total) || 0
- } finally {
- this.loading = false
- }
- },
- async loadMore() {
- if (this.loading || this.loadingMore || this.dataList.length >= this.tablePage.total) {
- return
- }
- this.loadingMore = true
- try {
- const nextPage = this.tablePage.currentPage + 1
- const data = await this.wareHouseService.wareHouseSummaryList({
- current: nextPage,
- size: this.tablePage.pageSize,
- orders: this.tablePage.orders,
- ...this.getSearchParams()
- })
- this.dataList = this.dataList.concat((data && data.records) || [])
- this.tablePage.currentPage = nextPage
- this.tablePage.total = (data && data.total) || this.tablePage.total
- } finally {
- this.loadingMore = false
- }
- },
- resetSearch() {
- this.searchForm = {
- wareHouseType: '',
- wareHouseTypeName: '',
- tradeName: '',
- supplierId: '',
- supplierName: ''
- }
- this.refreshList()
- },
- openTypePicker() {
- this.$refs.typePicker._show()
- },
- selectTypeChange(ids, names) {
- this.searchForm.wareHouseType = (ids && ids[0]) || ''
- this.searchForm.wareHouseTypeName = Array.isArray(names) ? names.join('/') : names
- this.refreshList()
- },
- openSupplierPicker() {
- this.$refs.supplierPicker.open()
- },
- selectSupplier(item) {
- this.searchForm.supplierId = item.id || ''
- this.searchForm.supplierName = item.name || ''
- this.refreshList()
- },
- clearSupplier() {
- this.searchForm.supplierId = ''
- this.searchForm.supplierName = ''
- this.refreshList()
- },
- formatNumber(value) {
- if (value === null || value === undefined || value === '') {
- return '0'
- }
- return value
- },
- calcBorrowNumber(row) {
- if (row.notSurplusStock && row.spec) {
- return this.trimNumber(parseFloat(row.notSurplusStock) / parseFloat(row.spec))
- }
- return '0'
- },
- calcLossNumber(row) {
- if (row.lossNumber && row.spec) {
- return this.trimNumber(parseFloat(row.lossNumber) / parseFloat(row.spec))
- }
- return '0'
- },
- trimNumber(value) {
- if (Number.isNaN(value)) {
- return '0'
- }
- return Number.isInteger(value) ? String(value) : value.toFixed(2)
- },
- async updateWarnFlag(row) {
- try {
- await this.wareHouseService.updateWarnFlagByTradeNameAndType(row.tradeName, row.wareHouseType)
- uni.showToast({
- title: '提醒状态已更新',
- icon: 'success'
- })
- this.refreshList()
- } catch (e) {
- this.refreshList()
- }
- },
- async changeWarnNum(row) {
- const warnNum = row.warnNum === '' || row.warnNum === null || row.warnNum === undefined ? 0 : row.warnNum
- try {
- await this.wareHouseService.updateWarnNumByTradeNameAndType(row.tradeName, row.wareHouseType, warnNum)
- uni.showToast({
- title: '提醒数量已更新',
- icon: 'success'
- })
- this.refreshList()
- } catch (e) {
- this.refreshList()
- }
- },
- openHistory(row) {
- this.$refs.historyPanel.open(row, this.searchForm.supplierId)
- },
- openEditTradeName(row) {
- this.$refs.editTradeNameDialog.open(row)
- }
- }
- }
- </script>
- <style scoped>
- .page-wrap {
- min-height: 100vh;
- padding: 20rpx 24rpx 48rpx;
- background: #f6f8fb;
- }
- .search-panel {
- padding: 22rpx;
- background: #fff;
- border-radius: 18rpx;
- box-shadow: 0 8rpx 24rpx rgba(15, 23, 42, 0.05);
- }
- .filter-row {
- display: grid;
- grid-template-columns: repeat(2, minmax(0, 1fr));
- gap: 16rpx;
- margin-top: 18rpx;
- }
- .filter-item {
- min-width: 0;
- padding: 18rpx 20rpx;
- background: #f8fafc;
- border-radius: 14rpx;
- }
- .filter-label {
- display: block;
- font-size: 22rpx;
- color: #64748b;
- }
- .filter-value {
- display: block;
- margin-top: 8rpx;
- font-size: 26rpx;
- color: #0f172a;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- .action-row {
- display: flex;
- gap: 16rpx;
- margin-top: 18rpx;
- }
- .action-button {
- flex: 1;
- }
- .summary-row {
- display: flex;
- justify-content: space-between;
- padding: 22rpx 4rpx 12rpx;
- font-size: 24rpx;
- color: #64748b;
- }
- .empty-state {
- padding: 120rpx 0;
- text-align: center;
- font-size: 28rpx;
- color: #94a3b8;
- }
- .stock-card {
- margin-bottom: 20rpx;
- padding: 24rpx;
- background: #fff;
- border-radius: 18rpx;
- box-shadow: 0 8rpx 24rpx rgba(15, 23, 42, 0.05);
- }
- .card-head {
- display: flex;
- align-items: flex-start;
- justify-content: space-between;
- gap: 16rpx;
- }
- .goods-name {
- flex: 1;
- font-size: 31rpx;
- font-weight: 700;
- line-height: 1.4;
- color: #0f172a;
- word-break: break-all;
- }
- .type-badge {
- max-width: 260rpx;
- padding: 8rpx 14rpx;
- border-radius: 999rpx;
- font-size: 22rpx;
- color: #1d4ed8;
- background: #dbeafe;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- .stock-main {
- display: flex;
- justify-content: space-between;
- gap: 20rpx;
- margin-top: 24rpx;
- padding: 22rpx;
- background: #f8fafc;
- border-radius: 16rpx;
- }
- .stock-number {
- display: flex;
- align-items: baseline;
- gap: 8rpx;
- }
- .number-label {
- font-size: 22rpx;
- color: #64748b;
- }
- .number-value {
- font-size: 46rpx;
- font-weight: 800;
- color: #0f766e;
- }
- .number-unit {
- font-size: 24rpx;
- color: #475569;
- }
- .stock-total {
- display: flex;
- flex-direction: column;
- gap: 8rpx;
- text-align: right;
- font-size: 24rpx;
- color: #475569;
- }
- .metric-grid {
- display: grid;
- grid-template-columns: repeat(2, minmax(0, 1fr));
- gap: 16rpx;
- margin-top: 18rpx;
- }
- .metric-item {
- min-width: 0;
- padding: 18rpx;
- background: #fbfdff;
- border: 1rpx solid #eef2f7;
- border-radius: 14rpx;
- }
- .metric-label {
- display: block;
- margin-bottom: 10rpx;
- font-size: 22rpx;
- color: #64748b;
- }
- .metric-value {
- font-size: 28rpx;
- font-weight: 600;
- color: #0f172a;
- }
- .warn-input {
- width: 100%;
- }
- .card-actions {
- display: grid;
- gap: 16rpx;
- margin-top: 18rpx;
- }
- .card-button {
- width: 100%;
- }
- .load-more {
- padding: 24rpx 0;
- text-align: center;
- font-size: 26rpx;
- color: #64748b;
- }
- </style>
|